Java中怎么实现悲观锁与乐观锁
一、悲观锁的实现
悲观锁是一种保守的锁策略,它假设在任何时候都会发生并发冲突,因此在访问共享资源之前先锁住它,确保其他线程无法修改它,直到当前线程完成操作。在 Java 中,可以使用 synchronized 关键字实现悲观锁。
1. 使用 synchronized 关键字
在 Java 中,synchronized 关键字可以用来实现悲观锁。它可以修饰方法或代码块,确保同一时间只有一个线程可以执行被修饰的方法或代码块。
javapublicsynchronizedvoynchronizedMethod(){/业务逻辑}
上面的代码示例中,synchronized 关键字修饰了一个方法,表示该方法在执行时会获取对象的锁,其他线程需要等待该线程执行完毕才能获得锁并执行。
2. 使用 ReentrantLock
除了 synchronized 关键字,还可以使用 Java 中的 Lock 接口及其实现类 ReentrantLock 来实现悲观锁。
`java
Lock lock = new ReentrantLock();
public void lockMethod() {
lock.lock();
try {
// 业务逻辑
} finally {
lock.unlock();
}
}
`
上面的代码示例中,使用 ReentrantLock 的 lock 方法获取锁,使用 unlock 方法释放锁。
3. 悲观锁的应用场景
悲观锁适用于冲突频繁的场景,当并发冲突较多时,使用悲观锁可以有效减少冲突,保证数据的一致性。悲观锁的性能一般较差,适用于读多写少的场景。
二、乐观锁的实现
乐观锁是一种乐观的锁策略,它认为在大部分情况下并发冲突是很少发生的,因此在访问共享资源之前不会加锁,而是在更新时检查数据的版本号或时间戳,如果发现数据已被其他线程修改,则放弃本次操作。在 Java 中,可以使用版本号或时间戳实现乐观锁。
1. 使用版本号实现乐观锁
使用版本号实现乐观锁的方式是,在数据模型中增加一个版本号字段,并在更新时将版本号加 1。在读取数据时,将版本号一同读取,并在更新时比对版本号是否相等,如果不相等说明数据已被其他线程修改,则放弃本次操作。
`java
public class OptimisticLock {
private int version;
private int data;
public synchronized void updateData(int newData) {
if (this.version == getVersion()) {
this.data = newData;
this.version++;
} else {
// 数据已被其他线程修改,放弃操作
}
}
public int getVersion() {
return version;
}
public int getData() {
return data;
}
}
`
上面的代码示例中,使用一个 version 字段存储版本号,当更新数据时,先比对 version 是否一致,如果一致则更新数据并增加 version,否则放弃操作。
2. 使用时间戳实现乐观锁
使用时间戳实现乐观锁的方式是,在数据模型中增加一个时间戳字段,并在更新时更新时间戳。在读取数据时,将时间戳一同读取,并在更新时比对时间戳是否一致,如果不一致说明数据已被其他线程修改,则放弃本次操作。
`java
public class OptimisticLock {
private long timestamp;
private int data;
public synchronized void updateData(int newData) {
if (this.timestamp == getTimestamp()) {
this.data = newData;
this.timestamp = System.currentTimeMillis();
} else {
// 数据已被其他线程修改,放弃操作
}
}
public long getTimestamp() {
return timestamp;
}
public int getData() {
return data;
}
}
`
上面的代码示例中,使用一个 timestamp 字段存储时间戳,当更新数据时,先比对 timestamp 是否一致,如果一致则更新数据并更新 timestamp,否则放弃操作。
3. 乐观锁的应用场景
乐观锁适用于冲突较少的场景,当并发冲突少且冲突概率低时,使用乐观锁可以减少锁的竞争,提高系统的并发性能。乐观锁的性能一般较好,适用于读多写多的场景。乐观锁一般适用于数据更新频率较低的情况下。
猜您想看
-
Ambari2.6安装部署Hadoop2.7的步骤
一、准备条件1...
2023年05月26日 -
为什么我的Steam游戏启动失败?
Steam游戏...
2023年05月03日 -
如何移植linux kernel及含busybox的yaffs2文件系统镜像
一、准备工作1...
2023年05月23日 -
如何使用Docker进行容器镜像加速?
如何使用Doc...
2023年04月16日 -
如何使用自动准星
一、自动准星的...
2023年05月15日 -
Qt如何实现ffmpeg音视频同步
,内容中不能出...
2023年05月26日