一、在等待 Condition 時,容許發生「虛假喚醒」,這一般做爲對基礎平臺語義的讓步。對於大多數應用程序,這帶來的實際影響很小,由於 Condition 應該老是在一個循環中被等待,並測試正被等待的狀態聲明。某個實現能夠隨意移除可能的虛假喚醒,但建議應用程序程序員老是假定這些虛假喚醒可能發生,所以老是在一個循環中等待。java
二、一個鎖內部能夠有多個Condition,即有多路等待和通知,能夠參看jdk1.5提供的Lock與Condition實現的可阻塞隊列的應用案例,從中除了要體味算法,還要體味面向對象的封裝。在傳統的線程機制中一個監視器對象上只能有一路等待和通知,要想實現多路等待和通知,必須嵌套使用多個同步監視器對象。(若是隻用一個Condition,兩個放的都在等,一旦一個放的進去了,那麼它通知可能會致使另外一個放接着往下走。)程序員
將傳統wait()和notify() 改寫成Condition方式,須要Lock配合使用。算法
/** * @Title: TraditionalThreadCommunication.java * @Package com.lh.threadtest.t4 * @Description: TODO * @author Liu * @date 2018年1月15日 下午9:28:23 * @version V1.0 */ package com.lh.threadtest.t10; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @ClassName: TraditionalThreadCommunication * @Description: 傳統線程同步通訊技術 * * 子線程循環10次,接着主線程循環100次,接着又回到子線程循環10次,接着再回到主線程 * 又循環100次,如此循環50次,請寫出程序。 * * 注意: * Lock比傳統線程模型中的synchronized方式更加面向對象,與生活中的鎖相似,鎖自己也應該是一個對象。 * 兩個線程執行的代碼片斷要實現同步互斥的效果,它們必須用同一個Lock對象。鎖是上在表明要操做的資源的類的內部方法中, * 而不是線程代碼中! * * 總結: * 須要用到共同數據(包括同步鎖)或共同算法的若干個方法應該歸在同一個類中,這種設計正好體現了 * 高類聚和程序的健壯性。 * * @author Liu * @date 2018年1月15日 下午9:28:23 * */ public class ConditionCommunication { public static void main(String[] args) { final Business business = new Business(); new Thread(new Runnable() { public void run() { for(int i = 1; i <= 50; i++){ try { business.sub(i); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); for(int i = 1; i <= 50; i++){ try { business.main(i); } catch (InterruptedException e) { e.printStackTrace(); } } } //不一樣點: //condition.business //business //將具備相似功能的業務代碼抽象到同一個類中 //下面兩個方法(sub/main)是互斥的,均是獨立的一個同步模塊,處於同一個互斥組(經過synchronized代表均屬於同一個類,同一時刻只能有一個線程持有該鎖) static class Business{ Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); //主線程和子線程切換執行的一個標識 boolean flag = true; void sub(int i) throws InterruptedException{ lock.lock(); try { // if(!flag){ //循環和if功能相仿,但更加完備 while(!flag){ //使當前線程等待... // this.wait(); condition.await(); } for(int j = 1; j <= 10; j++){ System.out.println("sub thread sequence of " + j + ", loop of " + i); } flag = false; //喚醒其它正在等待的線程 // this.notify(); condition.signal(); } finally { lock.unlock(); } } void main(int i) throws InterruptedException{ lock.lock(); try { // if(flag){ //循環和if功能相仿,但更加完備 while(flag){ //使當前線程等待... // this.wait(); condition.await(); } for(int j = 1; j <= 100; j++){ System.out.println("main thread sequence of " + j + ", loop of " + i); } flag = true; //喚醒其它正在等待的線程 // this.notify(); condition.signal(); } finally { lock.unlock(); } } } }
老大循環100次,而後老二循環10次,接着老三循環20次,又接着老大循環100次,老二又循環10次,老三又循環20次, 如此循環50次,請寫出程序。oop
/** * @Title: TraditionalThreadCommunication.java * @Package com.lh.threadtest.t4 * @Description: TODO * @author Liu * @date 2018年1月15日 下午9:28:23 * @version V1.0 */ package com.lh.threadtest.t10; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @ClassName: TraditionalThreadCommunication * @Description: java5條件阻塞Condition的應用 * * 老大循環100次,而後老二循環10次,接着老三循環20次, * 又接着老大循環100次,老二又循環10次,老三又循環20次, * 如此循環50次,請寫出程序。 * * @author Liu * @date 2018年1月15日 下午9:28:23 * */ public class ThreeConditionCommunication { public static void main(String[] args) { final Business business = new Business(); new Thread(new Runnable() { public void run() { for(int i = 1; i <= 50; i++){ try { business.sub2(i); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { public void run() { for(int i = 1; i <= 50; i++){ try { business.sub3(i); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); for(int i = 1; i <= 50; i++){ try { business.main(i); } catch (InterruptedException e) { e.printStackTrace(); } } } //不一樣點: //condition.business //business //將具備相似功能的業務代碼抽象到同一個類中 //下面兩個方法(sub/main)是互斥的,均是獨立的一個同步模塊,處於同一個互斥組(經過synchronized代表均屬於同一個類,同一時刻只能有一個線程持有該鎖) static class Business{ Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); //主線程和子線程切換執行的一個標識 int flag = 1; void sub3(int i) throws InterruptedException{ lock.lock(); try { // if(!flag){ //循環和if功能相仿,但更加完備 while(flag != 3){ //使當前線程等待... // this.wait(); condition3.await(); } for(int j = 1; j <= 20; j++){ System.out.println("sub3 thread sequence of " + j + ", loop of " + i); } flag = 1; //喚醒其它正在等待的線程 // this.notify(); condition.signal(); } finally { lock.unlock(); } } void sub2(int i) throws InterruptedException{ lock.lock(); try { // if(!flag){ //循環和if功能相仿,但更加完備 while(flag != 2){ //使當前線程等待... // this.wait(); condition2.await(); } for(int j = 1; j <= 10; j++){ System.out.println("sub2 thread sequence of " + j + ", loop of " + i); } flag = 3; //喚醒其它正在等待的線程 // this.notify(); condition3.signal(); } finally { lock.unlock(); } } void main(int i) throws InterruptedException{ lock.lock(); try { // if(flag){ //循環和if功能相仿,但更加完備 while(flag != 1){ //使當前線程等待... // this.wait(); condition.await(); } for(int j = 1; j <= 100; j++){ System.out.println("main thread sequence of " + j + ", loop of " + i); } flag = 2; //喚醒其它正在等待的線程 // this.notify(); condition2.signal(); } finally { lock.unlock(); } } } }
class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }
一、爲何要用兩個Condition,而不是一個?測試
喚醒的是取的,而不是放的,每次只能存取一個。若是隻用一個Condition,兩個放的都在等,一旦一個放的進去了,那麼它通知可能會致使另外一個放接着往下走。this
一、Condition通常須要依賴Lock使用,不能獨立發揮做用。spa
二、Condition做用至關於傳統線程中的wait()和notify()——線程間通訊。線程
三、wait()和notify()只能在synchronized塊中使用,一樣地,Condition的await()和signal()方法只能在lock.lock()和lock.unlock()內部使用。設計