![7fdf63b61cbca0bcc55fc1f9c4751c49.png](https://i-blog.csdnimg.cn/blog_migrate/050d8ed2389921a3380822c94c1c2961.jpeg)
了解Condition
JDK1.5中引入了java.util.concurrent.locks.Condition接口,用来替代wait/notify。wait/notify大家应该很了解,主要用来解决多线程的协调问题(等待/通知),但是其存在如下几个问题:
- 早唤醒问题:wait/notify是依赖Object+synchronized来实现,如果存在多个线程wait(),那么通过notify()方法只能唤醒一个线程,而且这个线程不一定是我们想要唤醒的线程,导致运行错误。如果通过notifyAll()方法唤醒,那么所有线程都会唤醒,就会存在不想唤醒的线程被唤醒,导致不必要的线程上下文切换,这也就是早唤醒问题。
- Object.wait(long)是否为超时唤醒问题。Object.wait(long)方法可能是通过notify唤醒也可能是超时唤醒,但是无法通过这方法区分。
JUC中的Condition中await()、signal()、signalAll()分别对应Object中的wait()、notify()、notifyAll()方法。但是Condition更加灵活,并且解决了上述两个问题。
Condition的使用
public class ConditionTest { public static void main(String[] args) { //JUC提供的工具锁 Lock lock = new ReentrantLock(); //创建conditionA Condition conditionA = lock.newCondition(); //创建conditionB Condition conditionB = lock.newCondition(); //WaitThreadA类的线程通过conditionA来实现等待 new WaitThreadA(lock, conditionA).start(); new WaitThreadA(lock, conditionA).start(); //WaitThreadB的线程通过conditionB来实现等待 new WaitThreadB(lock, conditionB).start(); //NotifyThreadA new NotifyThreadA(lock, conditionA).start(); } static class WaitThreadA extends Thread{ private Lock lock; private Condition condition; public WaitThreadA(Lock lock, Condition condition){ this.lock = lock; this.condition = condition; } @Override public void run() { lock.lock(); try { System.out.println("WaitA begin"); condition.await(); System.out.println("WaitA end"); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } } static class NotifyThreadA extends Thread{ private Lock lock; private Condition condition; public NotifyThreadA(Lock lock, Condition condition){ this.lock = lock; this.condition = condition; } @Override public void run() { lock.lock(); try { System.out.println("NotifyA begin"); condition.signalAll(); System.out.println("NotifyA end"); }finally { lock.unlock(); } } } static class WaitThreadB extends Thread{ private Lock lock; private Condition condition; public WaitThreadB(Lock lock, Condition condition){ this.lock = lock; this.condition = condition; } @Override public void run() { lock.lock(); try { System.out.println("WaitB begin"); condition.await(); System.out.println("WaitB end"); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } }}
![37c3f4f38273f7b2014de5d640605463.png](https://i-blog.csdnimg.cn/blog_migrate/ce780cdeecec31f972eec6a22149111e.jpeg)
运行结果
如代码所示,Condition实例通过Lock.newCondition()方法创建。Object.wait()/notify()要求其执行线程必须持有这些方法所属对象的内部锁,Condition也类似,其需要执行线程持有创建该Condition实例的显示锁(lock)。不同的是lock可以创建多个Condition,用来实现不同类型/条件的线程的等待/通知。如示例代码,NotifyThreadA类型线程通过conditionA实例仅仅用来通知WaitThreadA类型线程。如果使用Object.wait()/notify()只能通知所有持有该对象内部锁且处于wait状态的线程,无法按分类/条件唤醒。
Condition作用
第一节已经说明了,Condition解决wait/notify存在的两个问题,在这一节我们总结一下Condition是如何解决这两个问题的。
- 解决早唤醒问题:Condition可以通过Lock.newCondition()方法创建多个Condition实例,来实现不同类型/条件线程的等待/唤醒,所以只要使用合理,就不会存在通知到不应该通知的线程而导致的线程资源竞争和不必要的线程上下文切换。
- Object.wait(long)是否为超时唤醒问题:Condition中提供了awaitUntil(Date)方法,这个方法可以用于实现带超时时间限制的等待,其返回一个boolean值用来区分是等待超时还是被通知唤醒的。true表示被通知唤醒,false表示等待超时唤醒。
总结:目前实际应用中推荐使用Condition来代替wait/notify。
参考
《Java多线程实战指南(核心篇)》第五章——线程间协作
END
笔者是一位热爱互联网、热爱互联网技术、热于分享的年轻人,如果您跟我一样,我愿意成为您的朋友,分享每一个有价值的知识给您。喜欢作者的同学,点赞+转发+关注哦!