ReentrantLock的出现
在JDK1.6以前,synchronized是重量级锁,需要调用操作系统的函数实现。Doug Lea就开发了JUC(java.util.concurrent工具包),可以在API级别对线程进行同步,后面sun公司对synchronized进行了优化。
LockSupport.park & LockSupport.unpark
调用LockSupport的park方法会堵塞线程。底层是调用Unsafe类的park方法。要重新恢复线程需要调用LockSupport.unpark(thread)方法。
public static void park() {
U.park(false, 0L);
}
Unsafe类的 park()方法:如果isAbsolute为false,堵塞时间单位是纳秒;isAbsolute为true,堵塞时间单位是毫秒;time是堵塞时间。
public native void park(boolean isAbsolute, long time);
公平锁和非公平锁
ReentrantLock支持公平锁和非公平锁,默认是非公平锁,可以在实例化ReentrantLock时指定使用公平锁还是非公平锁。
//ReentrantLock的final属性,在构造函数进行初始化,Sync是ReentrantLock定义的抽象静态内部类
private final Sync sync;
//内部类Sync继承抽象队列同步器
abstract static class Sync extends AbstractQueuedSynchronizer{}
//无参构造函数,指定使用非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//如果fair为true,表示使用公平锁;如果fair为false,表示使用非公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
//调用Unsafe类的cas方法修改ReentrantLock的state变量的值。
protected final boolean compareAndSetState(int expect, int update) {
return U.compareAndSetInt(this, STATE, expect, update);
}
//非公平锁实现
static final class NonfairSync extends Sync {
//成功持有锁返回true,失败返回false。
final boolean initialTryLock() {
//获取当前线程
Thread current = Thread.currentThread();
//判断修改state的值是否成功
if (compareAndSetState(0, 1)) {
//将锁的持有者修改为当前线程
setExclusiveOwnerThread(current);
//成功持有锁返回true
return true;
//修改失败,判断持有锁的是否是当前线程
} else if (getExclusiveOwnerThread() == current) {
//如果是当前线程持有锁,可重入,计数加1。
int c = getState() + 1;
if (c < 0) // overflow
throw new Error("Maximum lock count exceeded");
//设置state的值
setState(c);
//成功持有锁返回true
return true;
} else
//持有锁失败返回false
return false;
}
/**
* 调用initialTryLock方法后,非可重入
*/
protected final boolean tryAcquire(int acquires) {
//如果当前锁没有被其他线程持有,并且当前线程修改state值为acquires成功
if (getState() == 0 && compareAndSetState(0, acquires)) {
//把锁的持有者修改为当前线程
setExclusiveOwnerThread(Thread.currentThread());
//持有锁成功返回true。
return true;
}
//持有锁失败返回false。
return false;
}
}
//公平锁实现
static final class FairSync extends Sync {
/**
* 锁没有被占用并且等待队列为空才会获取锁,不可重入
*/
final boolean initialTryLock() {
//当前线程
Thread current = Thread.currentThread();
//获取state变量的值
int c = getState();
//如果state等于0,表示锁没有被其他线程占有
if (c == 0) {
//如果当前没有其他线程在等待获取,并且cas修改state值成功
if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
//将锁的持有者修改为当前线程
setExclusiveOwnerThread(current);
//持有锁成功返回true。
return true;
}
} else if (getExclusiveOwnerThread() == current) {
if (++c < 0) // overflow
throw new Error("Maximum lock count exceeded");
//重入,修改state变量的值
setState(c);
//持有锁成功返回true。
return true;
}
//持有锁失败返回false。
return false;
}
/**
* 只有当前线程是等待队列的头结点或者等待队列是空,才能获取
*/
protected final boolean tryAcquire(int acquires) {
//判断锁是否被持有,是否是等待队列的头结点(或者等待队列为空),cas修改state的值是否成功
if (getState() == 0 && !hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
//将锁的持有者修改为当前线程
setExclusiveOwnerThread(Thread.currentThread());
//获取锁成功返回true。
return true;
}
//获取锁失败返回false。
return false;
}
}
lock()
占用锁
final void lock() {
//如果第一次获取锁失败,会进行第二次尝试
if (!initialTryLock())
acquire(1);
}
public final void acquire(int arg) {
//判断是否获取成功
if (!tryAcquire(arg))
acquire(null, arg, false, false, false, 0L);
}
/**
* node null 除非有重新获取条件
* arg 获取参数
* shared true表示共享模式 false表示独占模式
* interruptible 是否中断,中断的时候返回负数
* timed 是否使用等待时间
* time 如果使用等待时间,设置超时时间
* 如果获取成功,这个方法会返回正数,如果超时返回0,如果中断返回负数
*/
final int acquire(Node node, int arg, boolean shared,
boolean interruptible, boolean timed, long time) {
Thread current = Thread.currentThread();
byte spins = 0, postSpins = 0;
boolean interrupted = false, first = false;
Node pred = null;
for (;;) {
//第一次循环:first = false,node = null,pred = null,head = null
//第二次循环:first = false,node != null,node.prev = null, pred = null, head = null
//第三次循环:first = false,node != null,node.prev = null, pred = null, head != null
//第四次循环:first = false,node != null,node.prev != null, pred != null, head = pred⇒ first = true
//第五次循环:first = true
if (!first && (pred = (node == null) ? null : node.prev) != null &&
!(first = (head == pred))) {
if (pred.status < 0) {
cleanQueue();
continue;
} else if (pred.prev == null) {
Thread.onSpinWait();
continue;
}
}
//第一次循环first = false,pred = null, node = null
//第二次循环first = false,pred = null, node != null
if (first || pred == null) {
boolean acquired;
try {
if (shared)
//共享锁
acquired = (tryAcquireShared(arg) >= 0);
else
//独占锁
acquired = tryAcquire(arg);
} catch (Throwable ex) {
cancelAcquire(node, interrupted, false);
throw ex;
}
//如果有其他线程占有锁,返回false
if (acquired) {
if (first) {
node.prev = null;
head = node;
pred.next = null;
node.waiter = null;
if (shared)
signalNextIfShared(node);
if (interrupted)
current.interrupt();
}
return 1;
}
}
//第一次循环node为null,在这里进行实例化为独占结点
if (node == null) {
if (shared)
node = new SharedNode();
else
node = new ExclusiveNode();
//第二次循环node != null, pred = null,初始化头结点,尾结点,这时候头结点和尾结点指向的是同一个结点
//第三次循环node != null, pred = null,重新设置尾结点,将node变量结点设置为尾结点,前尾结点是node变量结点的前驱节点,通过setPrevRelaxed设置。由于第二次循环后头尾结点指向相同的结点,所以这时候node结点的prev结点和head结点指向相同的结点,即node.prev = head
//第四次循环node != null, pred != null,node设置为等待(WAITING)状态
//第五次循环
} else if (pred == null) {
//node结点的等待线程设置为当前线程
node.waiter = current;
//获取队列尾结点
Node t = tail;
//设置node的prev结点是尾结点
node.setPrevRelaxed(t);
//尾结点是空,初始化头结点。
if (t == null)
tryInitializeHead();
//cas设置尾结点为node结点
else if (!casTail(t, node))
//如果设置尾结点失败,将node的prev结点设置为null
node.setPrevRelaxed(null); // back out
else
//设置尾结点成功,将上一个尾结点的next结点设置为当前尾结点。
t.next = node;
} else if (first && spins != 0) {
--spins; // reduce unfairness on rewaits
Thread.onSpinWait();
//第四次循环:将node结点状态设置为等待(WAITING)状态
} else if (node.status == 0) {
node.status = WAITING; // enable signal and recheck
//第五次循环:调用LockSupport.part方法堵塞线程
} else {
long nanos;
spins = postSpins = (byte)((postSpins << 1) | 1);
if (!timed)
LockSupport.park(this);
else if ((nanos = time - System.nanoTime()) > 0L)
LockSupport.parkNanos(this, nanos);
else
break;
node.clearStatus();
if ((interrupted |= Thread.interrupted()) && interruptible)
break;
}
}
return cancelAcquire(node, interrupted, interruptible);
}
private void tryInitializeHead() {
//实例化一个独占结点
Node h = new ExclusiveNode();
//将头结点设置为这个独占结点,并设置尾结点
if (U.compareAndSetReference(this, HEAD, null, h))
tail = h;
}
unlock()
释放锁
//ReentrantLock.unlock()方法
public void unlock() {
//调用AbstractQueuedSynchronizer.release()方法
sync.release(1);
}
//以独占方式释放锁,arg表示释放的线程数量
public final boolean release(int arg) {
//判断当前线程是否已经释放锁(包括锁重入释放)
if (tryRelease(arg)) {
//唤醒队列的第一个线程
signalNext(head);
return true;
}
return false;
}
ReentrantLock抽象静态内部类Sync,重写了AbstractQueuedSynchronizer的tryRelease()方法。
protected final boolean tryRelease(int releases) {
//getState()方法获取state变量的值,因为ReentrantLock是锁是可重入的,这里需要判断重入释放次数
int c = getState() - releases;
//判断持有锁的线程是否是当前线程,如果不是,抛出IllegalMonitorStateException。
if (getExclusiveOwnerThread() != Thread.currentThread())
throw new IllegalMonitorStateException();
//如果c的值为0,设置空闲状态为true, 表示当前线程已经不再要占用这个锁了。
boolean free = (c == 0);
//如果锁处于空闲状态,设置锁持有者为null。
if (free)
setExclusiveOwnerThread(null);
//重新设置state变量的值
setState(c);
return free;
}
//唤醒下一个线程
private static void signalNext(Node h) {
Node s;
//如果参数h结点不为空,后继结点也不会空,状态不等于0。取消等待状态,调用unpark唤醒后继节点保存的线程
if (h != null && (s = h.next) != null && s.status != 0) {
//取消等待状态
s.getAndUnsetStatus(WAITING);
//s.waiter是后继结点保存的线程,unpack会取消线程的阻塞状态
LockSupport.unpark(s.waiter);
}
}