目录
3、await / awaitUninterruptibly
4、await / awaitNanos / awaitUntil
上一篇《Java8 ReentrantLock 源码解析》中主要讲解了lock和unlock相关方法的实现,本篇讲解ReentrantLock的newCondition方法返回的ConditionObject实例的使用和实现细节。
1、定义
ConditionObject是AbstractQueuedSynchronizer的一个内部类,用于实现Condition接口,ReentrantLock通过newCondition方法返回该类的一个实例,如下:
public Condition newCondition() {
return sync.newCondition();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
Condition接口定义的方法如下:
这里的await相当于Object的wait方法,signal和signalAll方法相当于Object的notify和notifyAll方法。concurrent包下各种阻塞队列和线程池等就是Condition接口实现阻塞,以await方法的调用链为例说明,如下:
ConditionObject只有两个属性:
- private transient Node firstWaiter; //在某个Condition实例上等待的Node链表的链表头,即调用了某个condition实例的await方法的等待线程链表
- private transient Node lastWaiter; //在某个Condition实例上等待的Node链表的链表尾
注意上述链表是通过Node的nextWaiter构成的单向链表,跟通过Node的prev,next属性构成的等待获取锁的同步链表是不一样的,后者的链表头和链表为分别是AbstractQueuedSynchronizer的head和tail属性。
ConditionObject还定义了两个常量,描述await方法退出时的处理方式,如下:
REINTERRUPT表示将当前线程的中断标识重置为true,因为之前获取线程是否中断时,会将线程的中断标识给清除掉重置为false,此处是为了还原;THROW_IE表示会抛出一个InterruptedException异常,表示当前线程被唤醒是因为被中断了。
2、使用
ConditionObject的await系列方法相当于Object的wait方法,signal和signalAll方法分别对应于Object的notify和notifyAll方法,跟Object一样,执行这些方法前都需要检查当前线程是否持有锁,如果没有持有则会抛出IllegalMonitorStateException异常,ConditionObject的方法和Object的对应方法的实现逻辑也大体一致,参考如下测试用例:
@Test
public void name2() throws Exception {
Object lock = new Object();
Runnable a = new Runnable() {
@Override
public void run() {
try {
System.out.println("run start,time->" + System.currentTimeMillis());
Thread.sleep(6000);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (lock) {
lock.notify();
System.out.println("run end");
}
}
};
Thread thread = new Thread(a);
thread.start();
synchronized (lock) {
System.out.println("main start,time->" + System.currentTimeMillis());
long start = System.currentTimeMillis();
lock.wait(1000);
System.out.println("wait time->" + (System.currentTimeMillis() - start));
}
System.out.println("main end");
}
@Test
public void name3() throws Exception {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Runnable a = new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("run start,time->" + System.currentTimeMillis());
Thread.sleep(6000);
condition.signal();
System.out.println("run end");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
};
Thread thread = new Thread(a);
lock.lock();
try {
thread.start();
System.out.println("main start,time->" + System.currentTimeMillis());
long start = System.currentTimeMillis();
condition.await(1, TimeUnit.SECONDS);
System.out.println("wait time->" + (System.currentTimeMillis() - start));
} finally {
lock.unlock();
}
System.out.println("main end");
}
这两个的执行结果一样,如下:
main start,time->1585901311285
run start,time->1585901311286
run end
wait time->6001
main end
wait方法明明最多等待1s,为啥实际等待了6s了,难道是1s后没有被唤醒?答案是调用await和wait方法都会释放当前占有的锁,然后阻塞当前线程;1s过了,阻塞的线程被唤醒了,因为await和wait方法后面的逻辑处于加锁的代码块中,所以线程被唤醒后需要重新去抢占锁,此时锁是被线程thread占用的,所以线程会被唤醒后尝试获取失败又继续被阻塞了,直到6s后thread线程释放锁并唤醒阻塞的main线程,main线程重新获取锁成功,才从await或者wait方法退出,执行下面的逻辑。
3、await / awaitUninterruptibly
await方法用于让当前线程阻塞,直到被唤醒或者被打断,如果被打断则抛出异常InterruptedException,awaitUninterruptibly会一直等待直到被唤醒,被打断时不会抛出异常,可以通过线程的中断标识判断是否因为中断被唤醒的,注意无论是被signal唤醒的还是被中断唤醒的,都需要再次获取锁才可以退出await方法。
public final void await() throws InterruptedException {
if (Thread.interrupted())
//如果线程已中断抛出异常
throw new InterruptedException();
//在ConditionWaiter链表末尾插入一个新的状态是CONDITION的节点
Node node = addConditionWaiter();
//释放占有的锁,并唤醒同步队列中下一个等待节点,如果当前线程未持有锁则抛出异常
int savedState = fullyRelease(node);
int interruptMode = 0;
//isOnSyncQueue判断node是否在等待获取锁的同步链表中,对于刚创建的ConditionWaiter节点,没有将其加入到等待获取锁的同步链表中
//只是将其加入到通过nextWaiter属性维护的等待链表中了,该方法返回false
//等该节点被signal方法唤醒后就会将其加入到同步链表中了,该方法返回true
while (!isOnSyncQueue(node)) {
//执行park让这个线程处于阻塞状态
LockSupport.park(this);
//线程被唤醒了,如果线程被中断的话,checkInterruptWhileWaiting的返回值就不是0,此时会退出循环,checkInterruptWhileWaiting在执行时会将当前节点加入到同步链表中
//如果不是被中断,则继续while循环
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//acquireQueued方法会尝试获取锁,如果失败则阻塞当前线程直到获取成功,返回值为true,表示最后一次唤醒是因为线程中断
//interruptMode为0或者REINTERRUPT
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
//从链表中移除所有非CONDITION的节点
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
public final void awaitUninterruptibly() {
//添加一个新的节点
Node node = addConditionWaiter();
//释放锁
int savedState = fullyRelease(node);
boolean interrupted = false;
//判断node是否在同步链表中
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
//如果线程被中断过将interrupted 置为true,此时会继续循环,直到被唤醒,node加入到同步链表中,while循环退出
if (Thread.interrupted())
interrupted = true;
}
//如果获取锁成功或者interrupted为true,将当前线程标记为已中断
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
//在链表末尾插入一个新的状态是CONDITION的节点,因为此时未释放锁,所以只有一个线程在操作waiter链表,不需要通过CAS修改lastWaiter属性
private Node addConditionWaiter() {
//获取最后一个节点
Node t = lastWaiter;
//如果t不是CONDITION,则从链表中移除所有非CONDITION的节点
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
//创建一个新节点
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
//链表为空
firstWaiter = node;
else
//插入到lastWaiter的后面
t.nextWaiter = node;
//重置lastWaiter
lastWaiter = node;
return node;
}
//会遍历一遍链表,清理掉所有不是CONDITION的节点
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
//trail表示上一个非CONDITION节点
Node trail = null;
//遍历整个链表
while (t != null) {
//获取下一个节点
Node next = t.nextWaiter;
if (t.waitStatus != Node.CONDITION) {
//将t从链表中移除
t.nextWaiter = null;
if (trail == null)
//未找到非CONDITION节点,即之前遍历的节点都被移除了
firstWaiter = next;
else
trail.nextWaiter = next;
if (next == null)
//遍历到末尾了,将tail置为lastWaiter
lastWaiter = trail;
}
else
trail = t;
t = next;
}
}
final int fullyRelease(Node node) {
boolean failed = true;
try {
//获取当前的同步器状态
int savedState = getState();
//release方法返回true,表示成功释放锁,返回false表示不能释放锁
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
//如果release方法返回false进入此分支,将状态置为CANCELLED
node.waitStatus = Node.CANCELLED;
}
}
protected final int getState() {
return state;
}
public final boolean release(int arg) {
//tryRelease是子类实现的方法,会校验当前线程是否持有锁,如果没有则抛出IllegalMonitorStateException异常,如果占有了则用state减去arge,如果等于0返回true,需要释放锁
if (tryRelease(arg)) {
//获取链表头
Node h = head;
//waitStatus初始值是0
if (h != null && h.waitStatus != 0)
//唤醒下一个不是CANCELLED的节点对应的线程
unparkSuccessor(h);
return true;
}
return false;
}
//isOnSyncQueue判断node是否在等待获取锁的同步链表中
final boolean isOnSyncQueue(Node node) {
//如果是CONDITION则需要从链表中移除
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
if (node.next != null) // If has successor, it must be on queue
return true;
//prev肯定不为空,但是next可能为空,比如该节点就是末尾节点
return findNodeFromTail(node);
}
//从tail开始往前遍历,判断目标节点是否在链表中
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
final boolean transferAfterCancelledWait(Node node) {
//如果状态是CONDITION,将其原子的置为0
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
//如果修改成功,将其加入到同步队列中,注意此时node还在等待链表中
enq(node);
return true;
}
//如果修改失败,说明其他某个线程修改了状态(另一个线程同时唤醒了此节点),则通过isOnSyncQueue方法判断其
//是否在同步队列中,如果不在则执行yeild,不断while循环,直到该方法返回true
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
private Node enq(final Node node) {
//for循环直到原子修改成功为止
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
//原子的设置head
tail = head;
} else {
//tail不为空,将新节点插入到tail的后面
node.prev = t;
if (compareAndSetTail(t, node)) {
//如果原子的修改成功
t.next = node;
return t;
}
}
}
}
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
//抛出异常
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
//重新中断当前线程
selfInterrupt();
}
测试用例如下:
@Test
public void test3() throws Exception {
ReentrantLock lock=new ReentrantLock();
Condition condition=lock.newCondition();
Thread a=new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
condition.await();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
a.start();
//让a线程执行起来
Thread.sleep(100);
Thread b=new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
Thread.sleep(5000);
condition.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
b.start();
//让b线程执行起来
Thread.sleep(100);
int i=0;
long start=System.currentTimeMillis();
while (a.isAlive()){
a.interrupt();
i++;
Thread.sleep(10);
}
System.out.println("main thread end,i->"+i+",time->"+(System.currentTimeMillis()-start));
}
执行结果如下:
在await方法退出前一共调用interrupt方法489次,从开始调用到await方法退出总耗时4904s,第一次调用interrupt方法会让当前线程从while循环中退出,然后进入到acquireQueued方法尝试获取锁,因为此时线程b在休眠过程中未释放锁,所以进入到acquireQueued方法后会被阻塞,后面每次调用interrupt方法都会唤醒线程然后重新尝试获取锁,直到获取成功为止,从acquireQueued方法退出。退出后因为interruptMode是THROW_IE,然后抛出InterruptedException异常。耗时4904ms是因为执行到start时,线程b实际已经运行了100ms左右,再过4900ms左右,就会执行signal唤醒在condition上等待的线程,线程a获取锁从await方法退出,main线程的while循环终止并退出。
将上述用例换成synchronized关键字,效果是一样的,如下:
@Test
public void test4() throws Exception {
Object lock=new Object();
Thread a=new Thread(new Runnable() {
@Override
public void run() {
try {
synchronized (lock) {
lock.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
a.start();
//让a线程执行起来
Thread.sleep(100);
Thread b=new Thread(new Runnable() {
@Override
public void run() {
try {
synchronized (lock) {
Thread.sleep(5000);
lock.notify();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
b.start();
//让b线程执行起来
Thread.sleep(100);
int i=0;
long start=System.currentTimeMillis();
while (a.isAlive()){
a.interrupt();
i++;
Thread.sleep(10);
}
System.out.println("main thread end,i->"+i+",time->"+(System.currentTimeMillis()-start));
}
如果换成awaitUninterruptibly方法,则不会抛出异常,此时可以通过线程的中断标识来判断是否是因为被中断唤醒的,如下:
@Test
public void test3() throws Exception {
ReentrantLock lock=new ReentrantLock();
Condition condition=lock.newCondition();
Thread a=new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
condition.awaitUninterruptibly();
System.out.println("interrupted->"+Thread.currentThread().isInterrupted());
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
a.start();
//让a线程执行起来
Thread.sleep(100);
Thread b=new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
Thread.sleep(5000);
condition.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
b.start();
//让b线程执行起来
Thread.sleep(100);
int i=0;
long start=System.currentTimeMillis();
while (a.isAlive()){
a.interrupt();
i++;
Thread.sleep(10);
}
System.out.println("main thread end,i->"+i+",time->"+(System.currentTimeMillis()-start));
}
测试结果如下:
4、await / awaitNanos / awaitUntil
上面的await是没有时间参数的,带时间参数的await方法有三个版本,await方法被中断唤醒后会尝试获取锁并抛出异常,如果是被signal唤醒的,则返回等待时间是否超时了,返回false表示等待超时了,true表示没有被超时。awaitNanos的实现跟await基本一致,就返回值不同,awaitNanos返回剩余的等待时间,如果为负值,表示等待超时了,否则未超时。awaitUntil的实现及返回值都和await一致,但是入参不同,await传递的是相对时间,从线程开始休眠算起,awaitUntil传递的是绝对时间,即具体的某一个时间点。
//返回是否因等待超时被唤醒,false表示等待超时了,true表示没有等待超时
public final boolean await(long time, TimeUnit unit)
throws InterruptedException {
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
//如果线程中断,则抛出异常
throw new InterruptedException();
//添加一个ConditionWaiter节点
Node node = addConditionWaiter();
//释放锁
int savedState = fullyRelease(node);
//计算等待的最迟期限
final long deadline = System.nanoTime() + nanosTimeout;
boolean timedout = false;
int interruptMode = 0;
//判断node是否在同步等待队列中
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
//等待的时间到了
timedout = transferAfterCancelledWait(node);
break;
}
//等待的时间较长,将线程park
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
//线程被唤醒,如果线程被中断则checkInterruptWhileWaiting返回1或者-1,终止循环
//如果是被signal方法唤醒则检查node是否在同步链表中,如果在则退出循环,尝试获取锁
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
//线程是被signal方法唤醒的,重新计算等待的时间
nanosTimeout = deadline - System.nanoTime();
}
//这部分逻辑跟不带参数的await方法一致
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
//awaitNanos的逻辑和带时间参数的await方法实现一致,就是返回值不同,返回剩余的等待时间
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return deadline - System.nanoTime();
}
//跟上面两个相比就是等待的时间不一致,上面两个是相对时间,从进入方法开始算起的,awaitUntil是绝对时间,即一个固定的时间点
public final boolean awaitUntil(Date deadline)
throws InterruptedException {
long abstime = deadline.getTime();
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (System.currentTimeMillis() > abstime) {
timedout = transferAfterCancelledWait(node);
break;
}
//abstime是绝对时间
LockSupport.parkUntil(this, abstime);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
测试用例如下:
@Test
public void test3() throws Exception {
ReentrantLock lock=new ReentrantLock();
Condition condition=lock.newCondition();
CountDownLatch countDownLatch=new CountDownLatch(1);
Thread a=new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
// boolean result=condition.await(6, TimeUnit.SECONDS);
// long result=condition.awaitNanos(TimeUnit.SECONDS.toNanos(4));
Calendar calendar= Calendar.getInstance();
calendar.add(Calendar.SECOND,5);
boolean result=condition.awaitUntil(calendar.getTime());
System.out.println("await result->"+result);
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
a.start();
//让a线程执行起来
Thread.sleep(100);
Thread b=new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
Thread.sleep(5000);
condition.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
b.start();
//让b线程执行起来
Thread.sleep(100);
long start=System.currentTimeMillis();
countDownLatch.await();
System.out.println("main thread end,time->"+(System.currentTimeMillis()-start));
}
5、signal / signalAll
signal和signalAll的核心都是transferForSignal方法,区别在于前者只处理firstWaiter一个节点,而signalAll会处理所有的节点。transferForSignal方法并不会直接唤醒等待中的线程,而是将其加入到等待获取锁的同步链表的后面,然后将该节点的前一个节点的状态改成SIGNAL,表示需要唤醒该节点。等同步链表前面的节点都获取锁并释放锁后,才会让该节点获取锁。
public final void signal() {
//如果没有获取锁,则抛出异常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
public final void signalAll() {
//如果没有获取锁,则抛出异常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) && //如果first是一个CANCLE节点,则transferForSignal返回false,然后通过while循环处理下一个节点
//否则返回true,终止循环
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
//将node的状态由CONDITION修改成0,如果修改失败,说明不是CONDITION而是CANCLE
//即node是一个无效节点
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
//将node插入到同步链表的末尾,返回链表中node的上一个节点,即插入前的tail节点
Node p = enq(node);
int ws = p.waitStatus;
//如果上一个节点是CANCLE,说明当前互斥锁未被占用,可唤醒当前线程获取锁
//将上一个tail节点状态为SIGNAL失败,说明该节点就是head节点,且head节点准备释放锁将状态置为0
//正常情形就是将p的状态修改成SIGNAL,
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
private void doSignalAll(Node first) {
//first本身就是firstWaiter,所以此处可以先将lastWaiter和firstWaiter置为null
lastWaiter = firstWaiter = null;
do {
//从first开始遍历所有的节点
Node next = first.nextWaiter;
first.nextWaiter = null;
//将目标节点加入到同步队列中
transferForSignal(first);
first = next;
} while (first != null);
}
测试用例如下:
@Test
public void test() throws Exception {
ReentrantLock lock=new ReentrantLock();
Condition condition=lock.newCondition();
CountDownLatch countDownLatch=new CountDownLatch(8);
Runnable wait=new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
lock.lock();
condition.await();
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+",await time->"+System.nanoTime());
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
};
for(int i=0;i<5;i++){
Thread thread=new Thread(wait);
thread.start();
}
//让上面5个线程运行起来并进入到await等待链表中
Thread.sleep(2000);
System.out.println("all wait thread start");
Thread a=new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
Thread.sleep(5000);
//根据awaiter队列的顺序,将await的线程加入到同步队列中
condition.signalAll();
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
a.start();
//让线程a运行起来,进入sleep
Thread.sleep(100);
//让线程b和线程c加入到同步队列中
Thread b=new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
lock.lock();
System.out.println(Thread.currentThread().getName()+",lock time->"+System.nanoTime());
Thread.sleep(1000);
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
b.start();
Thread c=new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
lock.lock();
System.out.println(Thread.currentThread().getName()+",lock time->"+System.nanoTime());
Thread.sleep(1000);
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
c.start();
countDownLatch.await();
System.out.println("main thread end");
}
其输出如下:
#从上到下,5个线程依次启动,并依次加入到await等待链表中
Thread-0,start time->2257452263025112
Thread-4,start time->2257452264363671
Thread-2,start time->2257452264494532
Thread-1,start time->2257452265047514
Thread-3,start time->2257452265350669
all wait thread start
//线程b和c都起来了,进入等待锁的同步链表中
Thread-6,start time->2257454364189121
Thread-7,start time->2257454364855324
//线程b和c依次获取锁
Thread-6,lock time->2257459262985730
Thread-7,lock time->2257460262757235
//5个线程按照加入到await等待链表中的顺序依次被唤醒获取锁
Thread-0,await time->2257461362593351
Thread-4,await time->2257461462572635
Thread-2,await time->2257461562551508
Thread-1,await time->2257461662549663
Thread-3,await time->2257461762404238
main thread end
在默认的非公平锁下,最早加入等待获取锁的同步链表中的线程优先获取锁,当在某个condition实例上等待的线程被唤醒后,是加入到同步链表的末尾等待获取锁;而synchronized的实现是相反的,最近加入到同步链表中的线程优先获取锁,当在某个Object实例上等待的线程被唤醒后,是加入到同步链表的前面,最近才加入到等待链表中线程在同步链表中的位置越靠前。测试用例如下:
@Test
public void test2() throws Exception {
Object lock=new Object();
CountDownLatch countDownLatch=new CountDownLatch(8);
Runnable wait=new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
synchronized (lock) {
lock.wait();
Thread.sleep(100);
}
System.out.println(Thread.currentThread().getName()+",await time->"+System.nanoTime());
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
};
for(int i=0;i<5;i++){
Thread thread=new Thread(wait);
thread.start();
}
Thread.sleep(2000);
System.out.println("all wait thread start");
Thread a=new Thread(new Runnable() {
@Override
public void run() {
try {
synchronized (lock) {
Thread.sleep(5000);
lock.notifyAll();
}
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
});
a.start();
Thread.sleep(100);
Thread b=new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ",lock time->" + System.nanoTime());
Thread.sleep(1000);
}
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
});
b.start();
Thread c=new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ",lock time->" + System.nanoTime());
Thread.sleep(1000);
}
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
});
c.start();
countDownLatch.await();
System.out.println("main thread end");
}
执行结果如下:
# 5个线程依次启动,进入等待链表中
Thread-0,start time->2257752210301534
Thread-1,start time->2257752211441136
Thread-4,start time->2257752213288373
Thread-2,start time->2257752213312986
Thread-3,start time->2257752214007084
all wait thread start
//线程 b和c依次启动,进入同步链表中
Thread-6,start time->2257754313978574
Thread-7,start time->2257754314997979
//线程a开始释放锁,notifyAll将所有等待链表中的节点按照相反的顺序加入到同步链表的前面
//按照同步链表的顺序依次唤醒线程,最近加入的优先被唤醒
Thread-3,await time->2257759311780596
Thread-2,await time->2257759411766853
Thread-4,await time->2257759511758033
Thread-1,await time->2257759611688911
Thread-0,await time->2257759711730959
Thread-7,lock time->2257759711767879
Thread-6,lock time->2257760711589432
main thread end
6、其他方法实现总结
ReentrantLock中有多个可以查看Condition等待队列状态的方法,其实现比较简单,这里总结如下:
- getWaitingThreads:获取在某个Condition实例上等待的线程列表,从firstWaiter开始往后遍历,将所有状态是CONDITION的节点对应的Thread加入到列表中并返回即可。
- getWaitQueueLength:获取在某个Condition实例上等待的线程的个数,遍历方式同上,不过此方法是计数累加
- hasWaiters:判断在某个Condition实例上是否有等待的线程,遍历方式同上,不过找到一个状态是CONDITION的节点即返回true