前言
在 多线程笔记(十):wait()/notify()/notifyAll() 的用法 中,我们有介绍了 wait()、notify()方法的使用。
在使用 Lock 锁之前,我们使用最多的同步方式就是 synchronized 关键字来实现同步方式了。然后配合 Object 的 wait()、notify()、notifyAll()方法,来实现线程的等待、唤醒操作
现在我们已经了解了基于JUC工具包的Lock锁、AQS、CAS 等内容后,我们再来介绍一下这个 Condition 接口。
Condition介绍
Condition 是伴随着JUC工具包,在Java 1.5 中才出现的。它用来替代传统的 Object 的 wait()、notify() 等来实现线程之间的协作。相比使用 Object 的 wait()、notify()、notifyAll(),使用 Condition的 await()、signal()、signalAll() 这种方式来实现线程之间的协作会更加的安全和高效。因为 Condition 也是基于AQS来实现的,所以通常来说比较推荐使用Condition,阻塞队列实际上是使用了Condition来模拟线程间协作。
Condition 是一个接口,常用的方法就是 await()、signal()和signalAll()方法了。如果你想使用 Condition来实现线程之间的协作,因为 Condition 依赖于 Lock 接口,我们需要使用 lock.newCondition() 的方式来生成一个 Condition 类,然后使用新建的condition类来调用 await()、signal()等方法。但是这些都必须在先获得锁的情况下操作,即这些操作必须在 lock.lock() 和 lock.unlock() 之间才可以使用。
对应关系 | Condition | Object |
等待 | await() | await() |
唤醒 | signal() | notify() |
唤醒全部等待线程 | signalAll() | notifyAll() |
使用操作过程
- Condition 提供了 await() 方法将当前线程阻塞,提供了 signal()方法用于其他线程将已经阻塞的一个线程唤醒,signalAll()方法唤醒所有阻塞的线程;
- Condition需要结合 Lock 来一起使用;
- 线程调用 await()方法前必须获得锁,调用 await()方法时,将线程构造成 Node 节点加入到 AQS 的等待队列,同时释放锁,并使用 LockSupport.park() 方式来挂起当前线程;
- 其他线程调用 signal() 方法前,也必须先获得锁。当执行 signal() 方法时将 Condition 等待队列的 Node 节点移入到 AQS 的同步队列,当获得锁的线程释放锁时,将唤醒 AQS 同步队列的下个节点,并将下个节点设置为 head 节点,移除上一个已经释放锁的线程
Condtion图示
Condition 提供的 await() 和 signal() 等方法,主要涉及到 AQS 同步队列 和 Condition 队列 之间等待线程关系交互。如下是两个队列具体干嘛的介绍。
Condition队列:用于存储处于等待状态的队列; AQS队列:用于存储即将要获得锁的线程。
如下图示过程,即为源码分析后得到的结果。为便于理解,此处不再进行源码分析。请看下图,你会很清楚的了解的。
Condition Demo
/**
* await()线程
*/
public class ThreadWait extends Thread {
private Lock lock;
private Condition condition;
public ThreadWait(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
try {
lock.lock();
System.out.println("开始执行 thread wait");
try {
condition.await();//此处有两个作用:1.使得当前的线程去阻塞 2.会释放锁(源码使用的LockSupport.unpark()方法)
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行结束 thread wait");
} finally {
lock.unlock();
}
}
}
/**
* signal()线程
*/
public class ThreadSignal extends Thread{
private Lock lock;
private Condition condition;
public ThreadSignal(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
try {
lock.lock();
System.out.println("开始执行 thread signal");
condition.signal();//阻塞
System.out.println("执行结束 thread signal");
} finally {
lock.unlock();
}
}
}
/**
* 测试await(),signal()
*/
public class test {
public static void main(String[] args) throws InterruptedException {
//定义Lock
Lock lock = new ReentrantLock();
//通过 lock.newCondition() 获得Condition对象(Lock和Condition必须同时使用)
Condition condition = lock.newCondition();
//Wait线程
ThreadWait waitThread = new ThreadWait(lock,condition);
waitThread.start();
//Signal线程
ThreadSignal notifyThread = new ThreadSignal(lock,condition);
notifyThread.start();
//Signal线程等待Wait线程启动(避免Signal线程先启动导致阻塞)
notifyThread.join();
}
}
测试结果
开始执行 thread wait
开始执行 thread signal
执行结束 thread signal
执行结束 thread wait
建议
请对比:多线程笔记(十):wait()/notify()/notifyAll() 的用法 学习
Condition 使用 + 原理分析,介绍到此为止
如果本文对你有所帮助,那就给我点个赞呗 ^_^
End