一、AbstractQueuedSynchronizer(AQS)框架
AQS是Java并发包中的基石,它为同步控制提供了一种框架。AQS并不直接实现任何同步接口,如lock、unlock、countDown等,但它定义了acquire和release两个方法来独占地(exclusive)获取和释放资源,以及acquireShared和releaseShared方法以共享的方式获取和释放资源。当调用ReentrantLock的lock方法时,实际上就是转交给Synchronizer的lock()方法。
二、ReentrantLock的实现
ReentrantLock是Java中的一个可重入锁,它继承了AQS的FairSync和NonfairSync两个子类。ReentrantLock允许同一线程多次获取同一把锁而不会产生死锁。ReentrantLock的lock过程主要涉及到AQS的acquire方法。
在ReentrantLock中,tryAcquire方法需要根据具体的同步需求来实现。当线程尝试获取锁时,如果当前锁的状态表示锁是空闲的(state为0),并且是第一个尝试获取锁的线程(对于非公平锁),那么它会尝试设置锁的状态并返回true。如果当前线程已经拥有锁(即重入),则直接增加锁的状态并返回true。否则,线程会被加入到AQS的等待队列中。
三、线程挂起与唤醒的底层机制
在Java中,线程的挂起与唤醒是通过Unsafe类的park和unpark方法实现的。Unsafe类是HotSpot JVM的一部分,提供了底层的操作系统原语。park方将当前线程挂起,等待被唤醒;unpark则会唤醒指定的线程。
在底层实现中,每个Java线程都有一个Parker实例。当线程被park时,它会将自己加入到一个等待队列中,并进入阻塞状态等待被唤醒。当调用unpark方法时,会发送一个信号给等待队列中的线程,这些线程收到信号后会从等待队列中移除并继续执行后续的代码。
这个过程涉及到多个系统调用的操作,包括futex系统调用等。Futex是一种用户空间与内核空间混合的同步机制,它允许在无竞争的情况下操作完全在用户空间进行,仅在发生竞争时才进入内核进行处理。
四、总结
本文通过对Java中ReentrantLock锁的详细解析,从AQS框架到ReentrantLock的具体实现,再到底层线程挂起与唤醒的机制进行了自上而下的梳理。希望能够帮助读者更好地理解Java并发编程中的锁机制及其底层实现原理。