Condition
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + ":1");
condition.await();
System.out.println(Thread.currentThread().getName() + ":2");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
try {
Thread.sleep(3000);
} catch (Exception e) {
}
lock.lock();
// 唤醒
condition.signal();
lock.unlock();
System.out.println(Thread.currentThread().getName() + ":3");
} |
Condition源码分析
Condition是一个接口,其提供的就两个核心方法,await和signal方法。分别对应着Object的wait和notify方法。调用Object对象的这两个方法,需要在同步代码块里面,即必须先获取到锁才能执行这两个方法。同理,Condition调用这两个方法,也必须先获取到锁
1.等待队列:用于存放在lock锁中调用await方法,当前线程会变为阻塞状态,
同时会释放锁 单向链表存放
- 同步队列:用于存放没有竞争到锁,采用双向链表存放。
等待池
Condition简单用法
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + ":1");
condition.await();
System.out.println(Thread.currentThread().getName() + ":2");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
try {
Thread.sleep(3000);
} catch (Exception e) {
}
lock.lock();
// 唤醒
condition.signal();
lock.unlock();
System.out.println(Thread.currentThread().getName() + ":3");
} |
Condition源码解读
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException(); // 将当前节点添加到最后一个节点
Node node = addConditionWaiter(); //释放锁的状态
long savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) { // 如果当前线程为-2 则当前线程变为阻塞状态
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
} //重新获取锁
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
} |
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException(); //获取单向链表,
Node first = firstWaiter;
if (first != null)
doSignal(first);
} condition是要和lock配合使用的也就是condition和Lock是绑定在一起的,而lock的实现原理又依赖于AQS,自然而然ConditionObject作为AQS的一个内部类无可厚非。我们知道在锁机制的实现上,AQS内部维护了一个同步队列,如果是独占式锁的话,所有获取锁失败的线程的尾插入到同步队列,同样的,condition内部也是使用同样的方式,内部维护了一个 等待队列,所有调用condition.await方法的线程会加入到等待队列中,并且线程状态转换为等待状态。另外注意到ConditionObject中有两个成员变量 内容太多了:这篇很详细 https://www.jianshu.com/p/730b6945bdfd Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition,阻塞队列实际上是使用了Condition来模拟线程间协作。
- Condition是个接口,基本的方法就是await()和signal()方法;
- Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
- 调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用
思考:为什么要加condition的方法,直接lock,unlock不就行了吗? 答案:https://zhuanlan.zhihu.com/p/86108783 condition的使用场景: 1. 调用condition.await方法后线程依次尾插入到等待队列中,如图队列中的线程引用依次为Thread-0,Thread-1,Thread-2....Thread-8;2. 等待队列是一个单向队列。通过我们的猜想然后进行实验验证,我们可以得出等待队列的示意图如下图所示:  每一行代码都有它的涵义,多问一句为什么;别怕,理清思路,一切代码都是数据的流动和转化,耐心一点,慢慢积累!一起加油!!! |