java面试题-乐观锁与悲观锁是什么?
引言
在并发编程中,为了确保共享数据的一致性和正确性,锁的使用是不可避免的。乐观锁和悲观锁是两种不同的锁策略,它们分别适用于不同的并发场景。本教程将深入研究乐观锁和悲观锁的概念、实现原理、适用场景以及通过示例代码演示它们的应用。
1. 悲观锁(Pessimistic Lock)
悲观锁是一种悲观地认为冲突一定会发生的锁策略。在处理共享数据时,线程每次都会上锁,其他线程在想要处理相同数据时会被阻塞,直到获取锁为止。常见的悲观锁实现包括使用synchronized
关键字。
1.1 悲观锁示例代码
public class PessimisticLockExample {
private int sharedData = 0;
// 使用悲观锁,synchronized关键字
public synchronized void updateSharedData() {
// 处理共享数据的业务逻辑
sharedData++;
}
}
在上述代码中,synchronized
关键字确保了对updateSharedData
方法的互斥访问,即一次只能有一个线程执行该方法,从而保证了共享数据的一致性。
2. 乐观锁(Optimistic Lock)
乐观锁是一种基于乐观假设的锁策略。在处理共享数据时,线程每次不会上锁,而是通过数据的版本号等机制判断其他线程是否更新了数据。最典型的乐观锁实现是使用CAS(Compare-and-Swap)操作。
2.1 乐观锁示例代码
import java.util.concurrent.atomic.AtomicInteger;
public class OptimisticLockExample {
private AtomicInteger sharedData = new AtomicInteger(0);
public void updateSharedData() {
int currentVersion = sharedData.get();
int newVersion = currentVersion + 1;
// 使用CAS操作更新数据
if (sharedData.compareAndSet(currentVersion, newVersion)) {
// 更新成功
System.out.println("Data updated successfully");
} else {
// 更新失败,可能有其他线程已经更新了数据,进行重试或其他处理
System.out.println("Data update failed. Retry or handle accordingly.");
}
}
}
在上述代码中,compareAndSet
方法是CAS操作的一种,用于判断当前版本与期望版本是否一致,如果一致,则更新数据。如果不一致,说明有其他线程已经更新了数据,需要进行重试或其他处理。
3. 乐观锁与悲观锁的优缺点比较
3.1 乐观锁的优点
- 适用于读多写少的场景,可以省去频繁加锁、释放锁的开销,提高吞吐量。
- 在无冲突的情况下,不会发生线程阻塞,减少线程切换的开销。
3.2 乐观锁的缺点
- 在写比较多的场景下,由于版本不一致,可能会产生大量的重试和自旋,导致CPU消耗增加,性能下降。
3.3 悲观锁的优点
- 适用于写多的场景,通过互斥访问保证了数据的一致性,避免了冲突。
- 不会产生重试和自旋,减少CPU消耗。
3.4 悲观锁的缺点
- 在读多的场景下,频繁加锁、释放锁的开销
较大,可能成为性能瓶颈。
总结
乐观锁和悲观锁是并发编程中常用的两种锁策略,各有优缺点。选择合适的锁策略取决于应用场景的读写比例以及对性能的要求。在实际应用中,有时也可以根据具体情况采用两者的结合策略,以兼顾各自优势。
正文到此结束
- 本文标签: Java 面试题
- 本文链接: https://www.jietongc.com/article/92
- 版权声明: 本文由大熊科技原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权