以前在寫顯示鎖的是後,在顯示鎖的接口中,提到了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
內容關於:併發編程
本文來源於網絡,只作技術分享,一律不負任何責任