ReentrantLock的公平锁与非公平锁的实现
ReentrantLock是jdk中提供的一种用于多线程同步的锁机制,相对于Synchronizes,提供了更加精确的控制功能,ReentrantLock提供了两种Sync内部实现类,分别是NonfairSync和fairSync,都是继承类Sync,类Sync又继承与AbstractQueuedSynchronizer,AbstractQueuedSynchronizer提供了锁机制实现的大部分功能,两者的类图如下,
ReentrantLock中提供了公平锁和非公平锁两种实现,默认是非公平锁,因为线程在唤醒后需要重新触发抢锁的动作,如果在唤醒新的线程前,有线程可以抢到锁,那么就无需唤醒等待队列中的线程,这样可以避免线程的唤醒操作,提高系统的性能。
注意:
正常情况下,公平锁和非公平锁都提供了等待队列的功能,新的线程如果没有获取到锁,那么就按照顺序加入到等待队列中,正在运行的线程的释放锁后,从等待队列中顺序唤醒线程。但是非公平锁则允许‘插队’:当一个线程请求非公平锁时,如果在发出请求的同时该锁变成可用状态,那么这个线程会跳过队列中所有的等待线程而获得锁。
AbstractQueuedSynchronizer存在一个变量,state,表示当前的锁是否被占用,1表示有一个线程被占用,2表示有一个线程两次调用了Lock()方法,
state变量则通过volatile+CAS操作保证了变量的线程安全性。
公平锁的实现如下:
/** * Sync object for fair locks */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { 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"); setState(nextc); return true; } return false; } }
acquire的函数会调用AbstractQueuedSynchronizer的acquire的函数,acquire中有会调用子类的tryAcquire方法,
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
在公平锁的tryAcquire函数中,会调用hasQueuedPredecessors()函数判断等待队列是否为空,或者自己是第一个等待Node,如果是那么返回true,如果不是那么返回false,将自己加入到等待队列中。
hasQueuedPredecessors的实现如下:
public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }
非公平锁的实现如下:
/** * Sync object for non-fair locks */ static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
nonfairTryAcquire的实现如下:
/** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
在非公平锁的lock函数和nonfairTryAcquire的函数中,会调用compareAndSetState(0, 1)方法,这是个CAS函数,如果当前的state的值为0,那么表明锁没有被抢占,
那么就获取,如果两次都获取失败,那么就将自己放入等待队列,如果获取成功,那么就直接执行代码,不用进入等待队列,这样就实现了抢占锁的机制。