面试(乐观锁和悲观锁)

一、锁

乐观锁(Optimistic Locking)和悲观锁(Pessimistic Locking)是在并发编程中常用的两种锁机制,用于解决多线程并发访问共享资源时的数据一致性问题。

二、乐观锁

乐观锁的基本思想是假设并发访问不会导致冲突,因此在读取数据时不加锁,只在更新数据时进行检查。乐观锁通常使用版本号或时间戳来实现。当一个线程要更新数据时,会先读取数据的版本号或时间戳,并将其保存下来。在提交更新时,会再次读取数据的版本号或时间戳进行比较,如果两次读取的值相同,则更新成功;如果不同,则说明数据被其他线程修改过,更新失败,需要进行相应的处理(如重试或回滚)。

三、悲观锁

悲观锁的基本思想是假设并发访问会导致冲突,因此在读取和更新数据时都会加上锁,避免其他线程修改数据。悲观锁通常使用排他锁(如独占锁)来实现,即一个线程获取到锁后,其他线程无法访问该资源,直到锁被释放。悲观锁的使用场景通常是对于更新操作频繁的情况,因为它会导致其他线程的阻塞和等待。

乐观锁和悲观锁各有其适用的场景:

  • 乐观锁适用于多读少写的场景,假设并发冲突的概率较小,可以提高并发性能。当发生冲突时,需要进行相应的处理,如重试。

  • 悲观锁适用于多写少读的场景,假设并发冲突的概率较大,需要确保数据的一致性。悲观锁的主要缺点是会引起线程的阻塞和等待,影响并发性能。

在实际应用中,选择使用乐观锁还是悲观锁需要根据具体的业务需求和并发场景进行评估和选择。

四、场景分析

4.1、操作系统

1、悲观锁:互斥锁

2、乐观锁:自旋锁

4.2、JAVA

4.2.1、synchronized锁

synchronized是Java中最基本的锁机制。它是通过在方法或代码块前加上关键字synchronized来实现的。当线程进入synchronized方法或代码块时,会自动获得锁,并在执行完毕后释放锁。synchronized锁是可重入的,也就是说一个线程可以多次获得同一把锁。

4.2.2、CAS

4.2.2.1、ReentrantLock锁:

ReentrantLock是Java.util.concurrent包中提供的一种可重入锁。它相比于synchronized锁更加灵活,提供了更多的高级特性。使用ReentrantLock锁需要手动获取和释放锁,可以通过lock()方法获取锁,通过unlock()方法释放锁。

4.2.2.2、ReadWriteLock锁:

ReadWriteLock是Java.util.concurrent包中提供的一种读写锁。它允许多个线程同时读共享资源,但只允许一个线程写共享资源。具体来说,当一个线程获得了写锁,其他线程无法同时获得读锁或写锁;当一个线程获得了读锁,其他线程可以同时获得读锁,但不能获得写锁。

4.2.2.3、LockSupport锁:

LockSupport是Java.util.concurrent包中提供的一种线程阻塞工具。它可以在线程内部对线程进行阻塞和唤醒操作,而不需要获取和释放锁。LockSupport通过park()方法阻塞线程,通过unpark()方法唤醒被阻塞的线程。

4.2.2.4、AtomicInteger锁:

AtomicInteger是Java.util.concurrent.atomic包中提供的一个线程安全的整数类。它通过原子操作来保证多线程环境下对整数的操作的原子性。AtomicInteger可以替代synchronized关键字,实现线程安全的自增、自减、比较等操作。

你可能感兴趣的:(面试,java,职场和发展)