可重入锁实现:给每一个锁关联一个获取计数值和一个所有者线程 非公平锁:抢占式,直接尝试修改state,获取锁 公平锁:先检查同步等待队列是否有等待的线程,先来先得
//构造函数,默认是非公平锁 public ReentrantLock() { sync = new NonfairSync(); } //指定策略 public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
先看看Sync这个类,继承自AQS:(因为默认是非公平模式,所以这里直接实现了非公平模式下的尝试获取锁)
//非公平模式尝试获取锁 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { //c=0,说明当前没有线程获取锁,CAS尝试设置state,获取锁 if (compareAndSetState(0, acquires)) { //抢占成功,将当前线程设置为独占模式 setExclusiveOwnerThread(current); return true; } } //到这里,说明锁已经被持有,检查持有锁的线程是否为当前线程 else if (current == getExclusiveOwnerThread()) { //如果是,累加重入次数 int nextc = c + acquires; //小于0 ,超过int的最大值了 if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); //设置state setState(nextc); return true; } //如果锁已经被抢占,并且持有线程不是当前线程,返回false。 return false; } //尝试释放锁 protected final boolean tryRelease(int releases) { //释放时,需要减去重入次数 int c = getState() - releases; //如果当前线程不是独占模式所有者,抛异常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { //c=0,释放完毕, free = true; //解除所有者关系 setExclusiveOwnerThread(null); } //设置重入次数 setState(c); return free; }
看看子类NonfairSync 非公平锁的实现:
final void lock() { //非公平锁,抢占模式,CAS直接尝试设置state,获取锁。 if (compareAndSetState(0, 1)) //获取成功,将当前线程设置为所有者 setExclusiveOwnerThread(Thread.currentThread()); else //CAS失败,在独占模式下请求。 acquire(1); } //非公平锁,尝试请求 protected final boolean tryAcquire(int acquires) { //直接调用父类方法 return nonfairTryAcquire(acquires); }
再看看子类FairSync 公平锁的实现:
final void lock() { acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ //公平锁的tryAcquire()。 //只有在递归(重入)或者同步队列中没有其他线程 //或者当前线程是等待队列中的第一个线程时,才允许访问。 protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { //如果c=0,说明锁没有被持有,需要检查同步等待队列中 //是否有其他线程,如果没有,尝试设置state if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { //设置成功,将当前线程设置为所有者 setExclusiveOwnerThread(current); return true; } } //锁已经被持有,且当前线程是所有者 else if (current == getExclusiveOwnerThread()) { //累计重入次数 int nextc = c + acquires; //超标 if (nextc < 0) throw new Error("Maximum lock count exceeded"); //设置state setState(nextc); return true; } return false; }
整理一下大概逻辑:
加锁操作:
非公平: 1.直接CAS抢占设置state,如果成功,获取锁成功。 2.如果获取失败,需要检查锁是否被其他线程持有 3.如果没有其他线程持有锁,会以CAS的方式尝试获取锁, ,如果成功,获取锁成功。 4.如果有其他线程持有锁,会检查一下持有锁的线程是否为当前线程 如果是,累加重入次数。 公平: 1.会先检查锁是否被其他线程持有,并且检查同步等待队列里有没有其他线程 2.如果没有其他线程持有锁,且同步等待队列里面没有其他线程,会以CAS的方式 尝试获取锁,CAS成功,获取锁成功。 3.如果有其他线程持有锁,检查是否为当前线程,如果是 累加重入次数,获取锁成功。 解锁操作: 1.当前线程先将重入次数减1,如果结果为0,将当前同步器的线程 信息清空,并唤醒同步等待队列中队列头的等待线程 2.如果重入次数减1后结果不为0(说明当前线程还持有当前锁),方法结束