日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java线程详解(16)-条件变量

發布時間:2025/3/21 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java线程详解(16)-条件变量 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 條件變量是Java5線程中很重要的一個概念,顧名思義,條件變量就是表示條件的一種變量。但是必須說明,這里的條件是沒有實際含義的,僅僅是個標記而已,并且條件的含義往往通過代碼來賦予其含義。

????????這里的條件和普通意義上的條件表達式有著天壤之別。

????????條件變量都實現了java.util.concurrent.locks.Condition接口,條件變量的實例化是通過一個Lock對象上調用newCondition()方法來獲取的,這樣,條件就和一個鎖對象綁定起來了。因此,Java中的條件變量只能和鎖配合使用,來控制并發程序訪問競爭資源的安全。

????????條件變量的出現是為了更精細控制線程等待與喚醒,在Java5之前,線程的等待與喚醒依靠的是Object對象的wait()和notify()/notifyAll()方法,這樣的處理不夠精細。

????????而在Java5中,一個鎖可以有多個條件,每個條件上可以有多個線程等待,通過調用await()方法,可以讓線程在該條件下等待。當調用signalAll()方法,又可以喚醒該條件下的等待的線程。有關Condition接口的API可以具體參考JavaAPI文檔。

????????條件變量比較抽象,原因是他不是自然語言中的條件概念,而是程序控制的一種手段。

????????下面以一個銀行存取款的模擬程序為例來揭蓋Java多線程條件變量的神秘面紗:

????????有一個賬戶,多個用戶(線程)在同時操作這個賬戶,有的存款有的取款,存款隨便存,取款有限制,不能透支,任何試圖透支的操作都將等待里面有足夠存款才執行操作。

import?java.util.concurrent.ExecutorService;?? import?java.util.concurrent.Executors;?? import?java.util.concurrent.locks.Condition;?? import?java.util.concurrent.locks.Lock;?? import?java.util.concurrent.locks.ReentrantLock;??/**?*?Java線程:條件變量?*/?? public?class?Test?{??public?static?void?main(String[]?args){??//創建并發訪問的賬戶??MyCount?myCount=new?MyCount("6215580000000000000",10000);??//創建一個線程池??ExecutorService?pool?=?Executors.newFixedThreadPool(2);??Thread?t1?=?new?SaveThread("張三",?myCount,?2000);??Thread?t2?=?new?SaveThread("李四",?myCount,?3600);??Thread?t3?=?new?DrawThread("王五",?myCount,?2700);??Thread?t4?=?new?SaveThread("老張",?myCount,?600);??Thread?t5?=?new?DrawThread("老牛",?myCount,?1300);??Thread?t6?=?new?DrawThread("胖子",?myCount,?800);??//執行各個線程??pool.execute(t1);??pool.execute(t2);??pool.execute(t3);??pool.execute(t4);??pool.execute(t5);??pool.execute(t6);??//關閉線程池??pool.shutdown();??}?? }?? //存款線程類?? class?SaveThread?extends?Thread?{??private?String?name;????????????//操作人??private?MyCount?myCount;????????//賬戶??private?int?x;??????????????????//存款金額??SaveThread(String?name,?MyCount?myCount,?int?x)?{??this.name?=?name;??this.myCount?=?myCount;??this.x?=?x;??}??public?void?run()?{??myCount.saving(x,?name);??}?? }?? //取款線程類?? class?DrawThread?extends?Thread?{??private?String?name;????????????????//操作人??private?MyCount?myCount;????????//賬戶??private?int?x;????????????????????????????//存款金額??DrawThread(String?name,?MyCount?myCount,?int?x)?{??this.name?=?name;??this.myCount?=?myCount;??this.x?=?x;??}??public?void?run()?{??myCount.drawing(x,?name);??}?? }?? //普通銀行賬戶,不可透支?? class?MyCount?{??private?String?oid;????????????????????????//賬號??private?int?cash;????????????????????????????//賬戶余額??private?Lock?lock?=new?ReentrantLock();?????????//賬戶鎖??private?Condition?_save?=?lock.newCondition();????//存款條件??private?Condition?_draw?=?lock.newCondition();????//取款條件??MyCount(String?oid,?int?cash)?{???????this.oid?=?oid;??this.cash?=?cash;??}??/**?*?存款?*?@param?x?存款金額?*?@param?name?存款人?*/??public?void?saving(int?x,String?name){??lock.lock();????????????????????????//獲取鎖??if?(x?>?0)?{??cash?+=?x;?//?存款??System.out.println(name?+?"存款"?+?x?+?",當前余額為"?+?cash);??}??_draw.signalAll();????????????//喚醒所有等待線程。??lock.unlock();????????????????????//釋放鎖??}??//取款??public?void?drawing(int?x,?String?name)?{??lock.lock();?????????????????????????????????//獲取鎖??try?{??if?(cash?-?x?<?0)?{??_draw.await();?//?阻塞取款操作??}?else?{??cash?-=?x;?//?取款??System.out.println(name?+?"取款"?+?x?+?",當前余額為"?+?cash);??}??_save.signalAll();?//?喚醒所有存款操作??}?catch?(InterruptedException?e)?{??e.printStackTrace();??}?finally?{??lock.unlock();?//?釋放鎖??}??}?? }??


????????執行結果:

張三存款2000,當前余額為12000?? 王五取款2700,當前余額為9300?? 老張存款600,當前余額為9900?? 老牛取款1300,當前余額為8600?? 胖子取款800,當前余額為7800?? 李四存款3600,當前余額為11400??


????????假如我們不用鎖和條件變量,如何實現此功能呢?下面是實現代碼:

import?java.util.concurrent.ExecutorService;?? import?java.util.concurrent.Executors;??/**?*?Java線程:不用條件變量?*/?? public?class?Test?{??public?static?void?main(String[]?args){??//創建并發訪問的賬戶??MyCount?myCount=new?MyCount("6215580000000000000",10000);??//創建一個線程池??ExecutorService?pool?=?Executors.newFixedThreadPool(2);??Thread?t1?=?new?SaveThread("張三",?myCount,?2000);??Thread?t2?=?new?SaveThread("李四",?myCount,?3600);??Thread?t3?=?new?DrawThread("王五",?myCount,?2700);??Thread?t4?=?new?SaveThread("老張",?myCount,?600);??Thread?t5?=?new?DrawThread("老牛",?myCount,?1300);??Thread?t6?=?new?DrawThread("胖子",?myCount,?800);??//執行各個線程??pool.execute(t1);??pool.execute(t2);??pool.execute(t3);??pool.execute(t4);??pool.execute(t5);??pool.execute(t6);??//關閉線程池??pool.shutdown();??}?? }?? //存款線程類?? class?SaveThread?extends?Thread?{??private?String?name;????????????//操作人??private?MyCount?myCount;????????//賬戶??private?int?x;??????????????????//存款金額??SaveThread(String?name,?MyCount?myCount,?int?x)?{??this.name?=?name;??this.myCount?=?myCount;??this.x?=?x;??}??public?void?run()?{??myCount.saving(x,?name);??}?? }?? //取款線程類?? class?DrawThread?extends?Thread?{??private?String?name;????????????????//操作人??private?MyCount?myCount;????????//賬戶??private?int?x;????????????????????????????//存款金額??DrawThread(String?name,?MyCount?myCount,?int?x)?{??this.name?=?name;??this.myCount?=?myCount;??this.x?=?x;??}??public?void?run()?{??myCount.drawing(x,?name);??}?? }?? //普通銀行賬戶,不可透支?? class?MyCount?{??private?String?oid;????????????????????????//賬號??private?int?cash;????????????????????????????//賬戶余額??MyCount(String?oid,?int?cash)?{???????this.oid?=?oid;??this.cash?=?cash;??}??/**?*?存款?*?@param?x?存款金額?*?@param?name?存款人?*/??public?synchronized?void?saving(int?x,Stringname){?????????if?(x?>?0)?{??cash?+=?x;?//?存款??System.out.println(name?+?"存款"?+?x?+?",當前余額為"?+?cash);??}??notifyAll();?//喚醒所有等待線程。??}??//取款??public?synchronized?void?drawing(int?x,?String?name){???????if?(cash?-?x?<?0)?{??try?{??wait();??}?catch?(InterruptedException?e)?{??e.printStackTrace();??}??}?else?{??cash?-=?x;?//?取款??System.out.println(name?+?"取款"?+?x?+?",當前余額為"?+?cash);??}??notifyAll();?//?喚醒所有存款操作???????}?? }??


????????執行結果:

張三存款2000,當前余額為12000?? 王五取款2700,當前余額為9300?? 李四存款3600,當前余額為12900?? 老牛取款1300,當前余額為11600?? 胖子取款800,當前余額為10800?? 老張存款600,當前余額為11400?

?
????????結合先前同步代碼知識,舉一反三,將此例改為同步代碼塊來實現,代碼如下:

import?java.util.concurrent.ExecutorService;?? import?java.util.concurrent.Executors;??/**?*?Java線程:改用同步代碼塊?*/?? public?class?Test?{??public?static?void?main(String[]?args){??//創建并發訪問的賬戶??MyCount?myCount=new?MyCount("6215580000000000000",10000);??//創建一個線程池??ExecutorService?pool?=?Executors.newFixedThreadPool(2);??Thread?t1?=?new?SaveThread("張三",?myCount,?2000);??Thread?t2?=?new?SaveThread("李四",?myCount,?3600);??Thread?t3?=?new?DrawThread("王五",?myCount,?2700);??Thread?t4?=?new?SaveThread("老張",?myCount,?600);??Thread?t5?=?new?DrawThread("老牛",?myCount,?1300);??Thread?t6?=?new?DrawThread("胖子",?myCount,?800);??//執行各個線程??pool.execute(t1);??pool.execute(t2);??pool.execute(t3);??pool.execute(t4);??pool.execute(t5);??pool.execute(t6);??//關閉線程池??pool.shutdown();??}?? }?? //存款線程類?? class?SaveThread?extends?Thread?{??private?String?name;????????????//操作人??private?MyCount?myCount;????????//賬戶??private?int?x;??????????????????//存款金額??SaveThread(String?name,?MyCount?myCount,?int?x)?{??this.name?=?name;??this.myCount?=?myCount;??this.x?=?x;??}??public?void?run()?{??myCount.saving(x,?name);??}?? }?? //取款線程類?? class?DrawThread?extends?Thread?{??private?String?name;????????????????//操作人??private?MyCount?myCount;????????//賬戶??private?int?x;???????????????????????????//存款金額??DrawThread(String?name,?MyCount?myCount,?int?x)?{??this.name?=?name;??this.myCount?=?myCount;??this.x?=?x;??}??public?void?run()?{??myCount.drawing(x,?name);??}?? }?? //普通銀行賬戶,不可透支?? class?MyCount?{??private?String?oid;????????????????????????//賬號??private?int?cash;????????????????????????????//賬戶余額??MyCount(String?oid,?int?cash)?{???????this.oid?=?oid;??this.cash?=?cash;??}??/**?*?存款?*?@param?x?存款金額?*?@param?name?存款人?*/??public?void?saving(int?x,String?name){????????if?(x?>?0)?{??synchronized?(this)?{??cash?+=?x;?//?存款??System.out.println(name?+?"存款"?+?x?+?",當前余額為"?+?cash);??notifyAll();?//喚醒所有等待線程。??}??}???????}??//取款??public?synchronized?void?drawing(int?x,?String?name)?{??????synchronized?(this)?{??if?(cash?-?x?<?0)?{??try?{??wait();??}catch?(InterruptedException?e)?{??e.printStackTrace();??}??}?else?{??cash?-=?x;?//?取款??System.out.println(name?+?"取款"?+?x?+?",當前余額為"?+?cash);??}???????????????}??notifyAll();?//?喚醒所有存款操作??}?? }??


????????執行結果:

李四存款3600,當前余額為13600?? 王五取款2700,當前余額為10900?? 老張存款600,當前余額為11500?? 老牛取款1300,當前余額為10200?? 胖子取款800,當前余額為9400?? 張三存款2000,當前余額為11400??


????????對比以上三種方式,從控制角度上講,第一種最靈活,第二種代碼最簡單,第三種容易犯錯。
?

總結

以上是生活随笔為你收集整理的Java线程详解(16)-条件变量的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。