以前在写显示锁的是后,在显示锁的接口中,提到了new Condition这个方法,这个方法会返回一个Condition对象html
简单介绍一下java
任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object上),主要包括wait()、wait(long timeout)、notify()以及notifyAll()方法,这些方法与synchronized同步关键字配合,能够实现等待/通知模式。以前写过一篇线程之间的协做(等待通知模式)是使用Object的wait和notify/notifyAll+Synchronized写的数据库
换而言之,synchronized关键字想要实现等待/通知模式,须要调用以上的四种方法。express
而后咱们的Condition接口也提供了可以实现等待/通知模式,是与Lock配合实现的。编程
我感受这个Condition和那个差很少,也是用来完成线程之间的协做的网络
可是两者在使用方式上以及功能特性上仍是有所差异的。并发
由此表能够看出,condition接口能够有多个等待队列,而object监视器方法只有一个队列,并且还不支持在等待状态响应中断,还不支持当前线程释放锁并进入等待状态到未来的某个时间。ide
也不打算写新的示例了,用这个Condition接口改造一下以前使用等待通知模式的那个案例吧post
Condition定义了等待/通知两种类型的方法,当前线程调用这些方法时,须要提早获取到Condition对象关联的锁。Condition对象是由Lock对象(调用Lock对象的newCondition()方法)建立出来的。其实就是,Condition是依赖Lock对象的。就像使用wait/notify须要依赖Synchronized锁同样,Condition的使用方式比较简单,须要注意在调用方法前获取锁测试
建立等待通知类
package org.dance.day4.condition; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 类说明:使用Condition接口实现等待通知模式 */ public class ExpressCond { public final static String CITY = "ShangHai"; /** * 快递运输里程数 */ private int km; /** * 快递到达地点 */ private String site; /** * 建立显示锁 */ private final Lock lock = new ReentrantLock(); /** * 检测城市变化 */ private final Condition siteCond = lock.newCondition(); /** * 检测千米数变化 */ private final Condition kmCond = lock.newCondition(); public ExpressCond() { } public ExpressCond(int km, String site) { this.km = km; this.site = site; } /* 变化千米数,而后通知处于wait状态并须要处理千米数的线程进行业务处理*/ public void changeKm() { // 获取锁 lock.lock(); try { this.km = 101; // 唤醒在kmCond 上 等待的线程 kmCond.signal(); } finally { lock.unlock(); } } /* 变化地点,而后通知处于wait状态并须要处理地点的线程进行业务处理*/ public void changeSite() { // 获取锁 lock.lock(); try { this.site = "BeiJing"; // 唤醒在siteCond 上 等待的线程 siteCond.signal(); } finally { lock.unlock(); } } /*当快递的里程数大于100时更新数据库*/ public void waitKm() { lock.lock(); try { while (this.km <= 100) { try { kmCond.await(); } catch (InterruptedException e) { // 处理线程中断 Thread.currentThread().interrupt(); e.printStackTrace(); } System.out.println("check km thread[" + Thread.currentThread().getId() + "] is be notifed."); } } finally { lock.unlock(); } System.out.println("the Km is " + this.km + ",I will change db"); } /*当快递到达目的地时通知用户*/ public void waitSite() { lock.lock(); try { while (CITY.equals(this.site)) { try { siteCond.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("check site thread[" + Thread.currentThread().getId() + "] is be notifed."); } } finally { lock.unlock(); } System.out.println("the site is " + this.site + ",I will call user"); } }
经过代码能够看见,咱们一个锁,是能够携带多个等待队列的
建立测试类
package org.dance.day4.condition; /** *类说明:测试Lock和Condition实现等待通知 */ public class TestCond { private static ExpressCond express = new ExpressCond(0,ExpressCond.CITY); /*检查里程数变化的线程,不知足条件,线程一直等待*/ private static class CheckKm extends Thread{ @Override public void run() { express.waitKm(); } } /*检查地点变化的线程,不知足条件,线程一直等待*/ private static class CheckSite extends Thread{ @Override public void run() { express.waitSite(); } } public static void main(String[] args) throws InterruptedException { for(int i=0;i<3;i++){ new CheckSite().start(); } for(int i=0;i<3;i++){ new CheckKm().start(); } Thread.sleep(1000); express.changeKm();//快递里程变化 } }
执行结果:
check km thread[14] is be notifed.
the Km is 101,I will change db
经过执行结果,咱们能够清晰的看到,他是直接唤醒了,在千米数变化上等待的线程的,在以前的等待通知模式中,也就是wait/notify/notifyAll+Sync实现的等待通知模式中,推荐你们使用notifyAll()来唤醒正在等待中的线程,可是在使用Condition接口中,推荐你们使用signal,而不是signalAll().为啥呢?由于wait/notify/notifyAll是Object的方法,在指定的对象中等待的多是多个线程,分别在检测不一样的变量,可能形成信号的拦截,因此推荐使用所有唤醒,,可是在使用Condition上却不是,由于他是多个等待队列,他清晰的知道本身应该唤醒那个线程,因此推荐使用signal,至于Condition的实现分析暂时先不写,等写完AQS再写方便,你们理解,我感受不是全部相关的知识都要堆在一块儿,要是理解不了,再深刻也没用
做者:彼岸舞
时间:2020\11\04
内容关于:并发编程
本文来源于网络,只作技术分享,一律不负任何责任