总结:
ReentrantLock 的基本实现可以概括为:先通过 CAS 尝试获取锁。如果此时已经有线程占据了锁,那就加入 AQS 队列并且被挂起。当锁被释放之后,排在 CLH 队列队首的线程会被唤醒,然后 CAS 再次尝试获取锁。在这个时候,如果:
非公平锁:如果同时还有另一个线程进来尝试获取,那么有可能会让这个线程抢先获取;
公平锁:如果同时还有另一个线程进来尝试获取,当它发现自己不是在队首的话,就会排到队尾,由队首的线程获取到锁。
ReentrantLock 主要利用 CAS + AQS队列来实现,通过重写了 AQS 的 tryAcquire 和 tryRelease方法实现的 lock 和 unlock。
Sync:抽象类,是 ReentrantLock 的内部类,继承自 AQS,实现了释放锁的操作(tryRelease()方法),并提供了 lock 抽象方法,由其子类实现。
Sync:抽象类,是 ReentrantLock 的内部类,继承自 AQS,实现了释放锁的操作(tryRelease()方法),并提供了 lock 抽象方法,由其子类实现。
NonfairSync:是 ReentrantLock的内部类,继承自 Sync,非公平锁的实现类。
FairSync:是 ReentrantLock 的内部类,继承自 Sync,公平锁的实现类。
非公平锁:
调用 lock 方法,当为非公平锁时,只要有线程过来就尝试获取锁,
如果获取成功
AQS的state==0 并且CAS写入成功,将自身设置为独占锁的拥有者
state != 0 但当前独占锁就是自身(表示重入),将state累加;
如果获取失败就将自己设置到 AQS 队列的尾部,等待唤醒;
公平锁:
当为公平锁时,与非公平锁的主要区别在于公平锁在执行 tryAcquire 时,需要加一个判断(当前节点是否还有其他节点),如果有其它节点则将自身添加到队列中等待唤醒;
源码:
public class ReentrantLock implements Lock, java.io.Serializable {private static final long serialVersionUID = 7373984872572414699L;/** Synchronizer providing all implementation mechanics */private final Sync sync;/*** Base of synchronization control for this lock. Subclassed* into fair and nonfair versions below. Uses AQS state to* represent the number of holds on the lock.*/abstract static class Sync extends AbstractQueuedSynchronizer {private static final long serialVersionUID = -5179523762034025860L;/*** Performs {@link Lock#lock}. The main reason for subclassing* is to allow fast path for nonfair version.*/abstract void lock();
参考