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

歡迎訪問 生活随笔!

生活随笔

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

java

Java线程详解(6)-线程的交互

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

線程交互是比較復雜的問題,SCJP要求不很基礎:給定一個場景,編寫代碼來恰當使用等待、通知和通知所有線程。

一、線程交互的基礎知識

? ? ? ? SCJP所要求的線程交互知識點需要從java.lang.Object的類的三個方法來學習:

void?notify()——喚醒在此對象監視器上等待的單個線程。?? void?notifyAll()——喚醒在此對象監視器上等待的所有線程。?? void?wait()——導致當前的線程等待,直到其他線程調用此對象的?notify()方法或?notifyAll()方法。??


????????當然,wait()還有另外兩個重載方法:

void?wait(longtimeout)——導致當前的線程等待,直到其他線程調用此對象的?notify()方法或?notifyAll()方法,或者超過指定的時間量。?? void?wait(longtimeout,?int?nanos)——導致當前的線程等待,直到其他線程調用此對象的?notify()方法或?notifyAll()方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量。?

?
????????以上這些方法是幫助線程傳遞線程關心的時間狀態。

????????關于等待/通知,要記住的關鍵點是:

????????必須從同步環境內調用wait()、notify()、notifyAll()方法。線程不能調用對象上等待或通知的方法,除非它擁有那個對象的鎖。

????????wait()、notify()、notifyAll()都是Object的實例方法。與每個對象具有鎖一樣,每個對象可以有一個線程列表,他們等待來自該信號(通知)。線程通過執行對象上的wait()方法獲得這個等待列表。從那時候起,它不再執行任何其他指令,直到調用對象的notify()方法為止。如果多個線程在同一個對象上等待,則將只選擇一個線程(不保證以何種順序)繼續執行。如果沒有線程等待,則不采取任何特殊操作。

????????下面看個例子就明白了:

/**?*?計算輸出其他線程鎖計算的數據?*/?? public?class?ThreadA?{??public?static?void?main(String[]?args)?{??ThreadB?b=new?ThreadB();??//啟動計算線程??b.start();??//線程A擁有b對象上的鎖。線程為了調用wait()或notify()方法,該線程必須是那個對象鎖的擁有者??synchronized?(b)?{??try?{??System.out.println("等待對象b完成計算......");??b.wait();??}?catch?(InterruptedException?e)?{??e.printStackTrace();??}??System.out.println("b對象計算的總和是:"?+?b.total);??}??}?? }??/**?*?計算1+2+3+...+100的和?*/?? public?class?ThreadB?extends?Thread?{??int?total;??public?void?run(){??synchronized?(this)?{??for?(int?i=0;i<101;i++){??total+=i;??}??//(完成計算了)喚醒在此對象監視器上等待的單個線程,在本例中線程A被喚醒??notify();??}??}?? }??


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

等待對象b完成計算......?? b對象計算的總和是:5050??


????????千萬注意:

????????當在對象上調用wait()方法時,執行該代碼的線程立即放棄它在對象上的鎖。然而調用notify()時,并不意味著這時線程會放棄其鎖。如果線程榮然在完成同步代碼,則線程在移出之前不會放棄鎖。因此,只要調用notify()并不意味著這時該鎖變得可用。

?

二、多個線程在等待一個對象鎖時候使用notifyAll()

? ? ? ? 在多數情況下,最好通知等待某個對象的所有線程。如果這樣做,可以在對象上使用notifyAll()讓所有在此對象上等待的線程沖出等待區,返回到可運行狀態。

????????舉個例子:

/**?*?計算線程?*/?? public?class?Calculator?extends?Thread?{??int?total;??@Override??public?void?run()?{??synchronized?(this)?{??for(int?i=0;i<101;i++){??total+=i;??}??}??//通知所有在此對象上等待的線程??notifyAll();??}???? }??/**?*?獲取計算結果并輸出?*/?? public?class?ReaderResult?extends?Thread?{??Calculator?c;??public?ReaderResult(Calculator?c)?{??this.c?=?c;??}??public?void?run(){??synchronized?(c)?{??try?{??System.out.println(Thread.currentThread()?+?"等待計算結果......");??c.wait();??}?catch?(InterruptedException?e)?{??e.printStackTrace();??}??System.out.println(Thread.currentThread()+?"計算結果為:"?+?c.total);??}??}??public?static?void?main(String[]?args)?{??Calculator?calculator=new?Calculator();??//啟動三個線程,分別獲取計算結果??new?ReaderResult(calculator).start();??new?ReaderResult(calculator).start();??new?ReaderResult(calculator).start();??//啟動計算線程??calculator.start();??}?? }??


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

Thread[Thread-1,5,main]等待計算結果......?? Thread[Thread-2,5,main]等待計算結果......?? Thread[Thread-3,5,main]等待計算結果......?? Exception?in?thread"Thread-0"?java.lang.IllegalMonitorStateException??atjava.lang.Object.notifyAll(Native?Method)??attest.Calculator.run(Calculator.java:15)?? Thread[Thread-3,5,main]計算結果為:5050?? Thread[Thread-2,5,main]計算結果為:5050?? Thread[Thread-1,5,main]計算結果為:5050??


????????運行結果表明,程序中有異常,并且多次運行結果可能有多種輸出結果。這就是說明,這個多線程的交互程序還存在問題。究竟是出了什么問題,需要深入的分析和思考,下面將做具體分析。

????????實際上,上面這個代碼中,我們期望的是讀取結果的線程在計算線程調用notifyAll()之前等待即可。但是,如果計算線程先執行,并在讀取結果線程等待之前調用了notify()方法,那么又會發生什么呢?這種情況是可能發生的。因為無法保證線程的不同部分將按照什么順序來執行。幸運的是當讀取線程運行時,它只能馬上進入等待狀態----它沒有做任何事情來檢查等待的事件是否已經發生。?----因此,如果計算線程已經調用了notifyAll()方法,那么它就不會再次調用notifyAll(),----并且等待的讀取線程將永遠保持等待。這當然是開發者所不愿意看到的問題。

????????因此,當等待的事件發生時,需要能夠檢查notifyAll()通知事件是否已經發生。

????????通常,解決上面問題的最佳方式是利用某種循環,該循環檢查某個條件表達式,只有當正在等待的事情還沒有發生的情況下,它才繼續等待。
?

總結

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

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