面试官:ReentrantLock了解么,AQS类是什么?
在Java中,ReentrantLock
是常用的锁机制,是一种可重入的互斥锁(Reentrant Mutual Exclusion Lock)。相对于synchronized
,它提供更多的灵活性、可扩展性和更高的并发性。
回答
ReentrantLock
内部使用了一个Sync
内部类实现了锁的基本功能。Sync
继承了AQS
类,通过对内部状态值的设置来保证互斥。
AbstractQueuedSynchronizer
是一个抽象类,它提供了一种多线程访问共享资源的机制,相当于是为锁提供了一个通用的框架。
Sync
内部维护了一个state
属性,表示当前的资源状态。当state
为 0 时,表示资源未被占用;当 state 大于 0 时,表示资源已被占用。- 调用
lock()
方法时,Sync
内部会通过compareAndSetState()
函数来尝试获取锁。如果获取锁失败,会将当前线程加入到等待队列中,等待唤醒后再次尝试获取锁。 - 调用
unlock()
方法时,会释放锁,并唤醒等待队列中的线程。 ReentrantLock
还实现了可重入特性。ReentrantLock 内部使用一个计数器来记录获得该锁的次数,每次unlock()
都会将计数器减一,只有计数器为 0 时才会真正释放锁。
AQS类
AQS
是Java中的一个同步工具,全称为AbstractQueuedSynchronizer
,它是Java并发包中其他同步工具的基础,例如ReentrantLock、CountDownLatch、Semaphore
等。
AQS
是一种实现线程同步的框架,它提供了一个队列,可以对这个队列中的元素进行加锁和释放锁的操作,以此来保证多个线程同步访问某个资源时的安全性。
AQS
的基本思想是,通过一个抽象类来实现同步器,该同步器维护了一个FIFO
队列,对该队列中的每个元素进行加锁或解锁操作,从而实现多线程对共享资源的同步访问。
通过继承AQS
类并实现它的抽象方法,可以实现多种锁和同步工具。AQS
的核心方法是acquire
和release
,它们定义了一种获取锁和释放锁的原子操作方式,具有较高的灵活性和扩展性。
ReentrantLock概述
ReentrantLock
是Java中一个可重入的互斥锁,被广泛应用于多线程并发控制场景。它允许线程在获得锁之后多次进入同一代码块,而不是简单的阻塞。ReentrantLock有一些特殊的方法,如lock()和unlock(),使得它更灵活,更可控和更适合细粒度的控制。同时,它允许多个线程同时访问锁,并具有公平和非公平锁两种机制,允许在竞争高的情况下提高并发性。
ReentrantLock底层实现
ReentrantLock
的底层实现基于AbstractQueuedSynchronizer
(AQS)。AQS是一个自旋锁的框架,提供多种锁的实现,如独占锁、共享锁等。AQS
的实现基于一种先进先出(FIFO)队列的方式,通过一个state变量来记录锁的状态,使其更高效。
ReentrantLock
是通过实现AQS
来实现锁的操作的。它基于AQS的独占锁机制,只允许一个线程获得锁。当一个线程获取了锁时,它就会将state
的值加1,如果这个线程再次请求这个锁时,它不需要再去获取锁,而是直接增加state
的值,并让线程进入等待状态,这个操作叫做重入。而这个线程释放锁时,则会将state
的值减1,当state
的值为0时,这个锁就能被其他的线程获取。
由于AQS
是基于类似于自旋锁的方式实现的,所以干等锁的线程是处于阻塞状态,而是处于循环等待的状态。这种方式可以避免线程进入睡眠状态以及线程上下文切换所带来的开销,使得锁的获得更快速,同时也减少了系统开销。
转载自:https://juejin.cn/post/7212889505371930684