成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

怎么在Java中正確使用wait,notify和notifyAll

這篇文章將為大家詳細(xì)講解有關(guān)怎么在Java中正確使用wait, notify和notifyAll,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

成都創(chuàng)新互聯(lián)是工信部頒發(fā)資質(zhì)IDC服務(wù)器商,為用戶(hù)提供優(yōu)質(zhì)的綿陽(yáng)電信機(jī)房服務(wù)

wait, notify 和 notifyAll,這些在多線(xiàn)程中被經(jīng)常用到的保留關(guān)鍵字,在實(shí)際開(kāi)發(fā)的時(shí)候很多時(shí)候卻并沒(méi)有被大家重視。本文對(duì)這些關(guān)鍵字的使用進(jìn)行了描述。

在 Java 中可以用 wait、notify 和 notifyAll  來(lái)實(shí)現(xiàn)線(xiàn)程間的通信。。舉個(gè)例子,如果你的Java程序中有兩個(gè)線(xiàn)程——即生產(chǎn)者和消費(fèi)者,那么生產(chǎn)者可以通知消費(fèi)者,讓消費(fèi)者開(kāi)始消耗數(shù)據(jù),因?yàn)殛?duì)列緩 沖區(qū)中有內(nèi)容待消費(fèi)(不為空)。相應(yīng)的,消費(fèi)者可以通知生產(chǎn)者可以開(kāi)始生成更多的數(shù)據(jù),因?yàn)楫?dāng)它消耗掉某些數(shù)據(jù)后緩沖區(qū)不再為滿(mǎn)。

我們可以利用wait()來(lái)讓一個(gè)線(xiàn)程在某些條件下暫停運(yùn)行。例如,在生產(chǎn)者消費(fèi)者模型中,生產(chǎn)者線(xiàn)程在緩沖區(qū)為滿(mǎn)的時(shí)候,消費(fèi)者在緩沖區(qū)為空的時(shí) 候,都應(yīng)該暫停運(yùn)行。如果某些線(xiàn)程在等待某些條件觸發(fā),那當(dāng)那些條件為真時(shí),你可以用 notify 和 notifyAll  來(lái)通知那些等待中的線(xiàn)程重新開(kāi)始運(yùn)行。不同之處在于,notify 僅僅通知一個(gè)線(xiàn)程,并且我們不知道哪個(gè)線(xiàn)程會(huì)收到通知,然而 notifyAll  會(huì)通知所有等待中的線(xiàn)程。換言之,如果只有一個(gè)線(xiàn)程在等待一個(gè)信號(hào)燈,notify和notifyAll都會(huì)通知到這個(gè)線(xiàn)程。但如果多個(gè)線(xiàn)程在等待這個(gè)信 號(hào)燈,那么notify只會(huì)通知到其中一個(gè),而其它線(xiàn)程并不會(huì)收到任何通知,而notifyAll會(huì)喚醒所有等待中的線(xiàn)程。

如何使用Wait

盡管關(guān)于wait和notify的概念很基礎(chǔ),它們也都是Object類(lèi)的函數(shù),但用它們來(lái)寫(xiě)代碼卻并不簡(jiǎn)單。如果你在面試中讓?xiě)?yīng)聘者來(lái)手寫(xiě)代碼, 用wait和notify解決生產(chǎn)者消費(fèi)者問(wèn)題,我?guī)缀蹩梢钥隙ㄋ麄冎械拇蠖鄶?shù)都會(huì)無(wú)所適從或者犯下一些錯(cuò)誤,例如在錯(cuò)誤的地方使用  synchronized 關(guān)鍵詞,沒(méi)有對(duì)正確的對(duì)象使用wait,或者沒(méi)有遵循規(guī)范的代碼方法。說(shuō)實(shí)話(huà),這個(gè)問(wèn)題對(duì)于不常使用它們的程序員來(lái)說(shuō)確實(shí)令人感覺(jué)比較頭疼。

***個(gè)問(wèn)題就是,我們?cè)趺丛诖a里使用wait()呢?因?yàn)閣ait()并不是Thread類(lèi)下的函數(shù),我們并不能使用 Thread.call()。事實(shí)上很多Java程序員都喜歡這么寫(xiě),因?yàn)樗鼈兞?xí)慣了使用Thread.sleep(),所以他們會(huì)試圖使用wait()   來(lái)達(dá)成相同的目的,但很快他們就會(huì)發(fā)現(xiàn)這并不能順利解決問(wèn)題。正確的方法是對(duì)在多線(xiàn)程間共享的那個(gè)Object來(lái)使用wait。在生產(chǎn)者消費(fèi)者問(wèn)題中,這 個(gè)共享的Object就是那個(gè)緩沖區(qū)隊(duì)列。

第二個(gè)問(wèn)題是,既然我們應(yīng)該在synchronized的函數(shù)或是對(duì)象里調(diào)用wait,那哪個(gè)對(duì)象應(yīng)該被synchronized呢?答案是,那個(gè) 你希望上鎖的對(duì)象就應(yīng)該被synchronized,即那個(gè)在多個(gè)線(xiàn)程間被共享的對(duì)象。在生產(chǎn)者消費(fèi)者問(wèn)題中,應(yīng)該被synchronized的就是那個(gè) 緩沖區(qū)隊(duì)列。(我覺(jué)得這里是英文原文有問(wèn)題……本來(lái)那個(gè)句末就不應(yīng)該是問(wèn)號(hào)不然不太通……)

怎么在Java中正確使用wait, notify和notifyAll

永遠(yuǎn)在循環(huán)(loop)里調(diào)用 wait 和 notify,不是在 If 語(yǔ)句

現(xiàn)在你知道wait應(yīng)該永遠(yuǎn)在被synchronized的背景下和那個(gè)被多線(xiàn)程共享的對(duì)象上調(diào)用,下一個(gè)一定要記住的問(wèn)題就是,你應(yīng)該永遠(yuǎn)在 while循環(huán),而不是if語(yǔ)句中調(diào)用wait。因?yàn)榫€(xiàn)程是在某些條件下等待的——在我們的例子里,即“如果緩沖區(qū)隊(duì)列是滿(mǎn)的話(huà),那么生產(chǎn)者線(xiàn)程應(yīng)該等 待”,你可能直覺(jué)就會(huì)寫(xiě)一個(gè)if語(yǔ)句。但if語(yǔ)句存在一些微妙的小問(wèn)題,導(dǎo)致即使條件沒(méi)被滿(mǎn)足,你的線(xiàn)程你也有可能被錯(cuò)誤地喚醒。所以如果你不在線(xiàn)程被喚 醒后再次使用while循環(huán)檢查喚醒條件是否被滿(mǎn)足,你的程序就有可能會(huì)出錯(cuò)——例如在緩沖區(qū)為滿(mǎn)的時(shí)候生產(chǎn)者繼續(xù)生成數(shù)據(jù),或者緩沖區(qū)為空的時(shí)候消費(fèi)者 開(kāi)始小號(hào)數(shù)據(jù)。所以記住,永遠(yuǎn)在while循環(huán)而不是if語(yǔ)句中使用wait!我會(huì)推薦閱讀《Effective Java》,這是關(guān)于如何正確使用wait和notify的***的參考資料。

基于以上認(rèn)知,下面這個(gè)是使用wait和notify函數(shù)的規(guī)范代碼模板:

// The standard idiom for calling the wait method in Java synchronized (sharedObject) {     while (condition) { sharedObject.wait();         // (Releases lock, and reacquires on wakeup)     }     // do action based upon condition e.g. take or put into queue }

就像我之前說(shuō)的一樣,在while循環(huán)里使用wait的目的,是在線(xiàn)程被喚醒的前后都持續(xù)檢查條件是否被滿(mǎn)足。如果條件并未改變,wait被調(diào)用之前notify的喚醒通知就來(lái)了,那么這個(gè)線(xiàn)程并不能保證被喚醒,有可能會(huì)導(dǎo)致死鎖問(wèn)題。

Java wait(), notify(), notifyAll() 范例

下面我們提供一個(gè)使用wait和notify的范例程序。在這個(gè)程序里,我們使用了上文所述的一些代碼規(guī)范。我們有兩個(gè)線(xiàn)程,分別名為 PRODUCER(生產(chǎn)者)和CONSUMER(消費(fèi)者),他們分別繼承了了Producer和Consumer類(lèi),而Producer和 Consumer都繼承了Thread類(lèi)。Producer和Consumer想要實(shí)現(xiàn)的代碼邏輯都在run()函數(shù)內(nèi)。Main線(xiàn)程開(kāi)始了生產(chǎn)者和消費(fèi) 者線(xiàn)程,并聲明了一個(gè)LinkedList作為緩沖區(qū)隊(duì)列(在Java中,LinkedList實(shí)現(xiàn)了隊(duì)列的接口)。生產(chǎn)者在***循環(huán)中持續(xù)往 LinkedList里插入隨機(jī)整數(shù)直到LinkedList滿(mǎn)。我們?cè)趙hile(queue.size ==  maxSize)循環(huán)語(yǔ)句中檢查這個(gè)條件。請(qǐng)注意到我們?cè)谧鲞@個(gè)檢查條件之前已經(jīng)在隊(duì)列對(duì)象上使用了synchronized關(guān)鍵詞,因而其它線(xiàn)程不能在 我們檢查條件時(shí)改變這個(gè)隊(duì)列。如果隊(duì)列滿(mǎn)了,那么PRODUCER線(xiàn)程會(huì)在CONSUMER線(xiàn)程消耗掉隊(duì)列里的任意一個(gè)整數(shù),并用notify來(lái)通知 PRODUCER線(xiàn)程之前持續(xù)等待。在我們的例子中,wait和notify都是使用在同一個(gè)共享對(duì)象上的。

import java.util.LinkedList; import java.util.Queue; import java.util.Random; /** * Simple Java program to demonstrate How to use wait, notify and notifyAll() * method in Java by solving producer consumer problem. * * @author Javin Paul */ public class ProducerConsumerInJava { public static void main(String args[]) {   System.out.println("How to use wait and notify method in Java");   System.out.println("Solving Producer Consumper Problem");   Queue<Integer> buffer = new LinkedList<>();   int maxSize = 10;   Thread producer = new Producer(buffer, maxSize, "PRODUCER");   Thread consumer = new Consumer(buffer, maxSize, "CONSUMER");   producer.start(); consumer.start(); } } /** * Producer Thread will keep producing values for Consumer * to consumer. It will use wait() method when Queue is full * and use notify() method to send notification to Consumer * Thread. * * @author WINDOWS 8 * */ class Producer extends Thread { private Queue<Integer> queue;   private int maxSize;   public Producer(Queue<Integer> queue, int maxSize, String name){    super(name); this.queue = queue; this.maxSize = maxSize;   }   @Override public void run()   {    while (true)     {      synchronized (queue) {       while (queue.size() == maxSize) {        try {         System.out .println("Queue is full, " + "Producer thread waiting for " + "consumer to take something from queue");         queue.wait();        } catch (Exception ex) {         ex.printStackTrace(); }        }        Random random = new Random();        int i = random.nextInt();        System.out.println("Producing value : " + i); queue.add(i); queue.notifyAll();       }      }     }    } /** * Consumer Thread will consumer values form shared queue. * It will also use wait() method to wait if queue is * empty. It will also use notify method to send * notification to producer thread after consuming values * from queue. * * @author WINDOWS 8 * */ class Consumer extends Thread {   private Queue<Integer> queue;   private int maxSize;   public Consumer(Queue<Integer> queue, int maxSize, String name){    super(name);    this.queue = queue;    this.maxSize = maxSize;   }   @Override public void run() {    while (true) {     synchronized (queue) {      while (queue.isEmpty()) {       System.out.println("Queue is empty," + "Consumer thread is waiting" + " for producer thread to put something in queue");       try {        queue.wait();       } catch (Exception ex) {        ex.printStackTrace();       }      }      System.out.println("Consuming value : " + queue.remove()); queue.notifyAll();     }    }   } }

怎么在Java中正確使用wait, notify和notifyAll

為了更好地理解這個(gè)程序,我建議你在debug模式里跑這個(gè)程序。一旦你在debug模式下啟動(dòng)程序,它會(huì)停止在PRODUCER或者 CONSUMER線(xiàn)程上,取決于哪個(gè)線(xiàn)程占據(jù)了CPU。因?yàn)閮蓚€(gè)線(xiàn)程都有wait()的條件,它們一定會(huì)停止,然后你就可以跑這個(gè)程序然后看發(fā)生什么了 (很有可能它就會(huì)輸出我們以上展示的內(nèi)容)。你也可以使用Eclipse里的Step into和Step over按鈕來(lái)更好地理解多線(xiàn)程間發(fā)生的事情。

本文重點(diǎn):

1. 你可以使用wait和notify函數(shù)來(lái)實(shí)現(xiàn)線(xiàn)程間通信。你可以用它們來(lái)實(shí)現(xiàn)多線(xiàn)程(>3)之間的通信。

2. 永遠(yuǎn)在synchronized的函數(shù)或?qū)ο罄锸褂脀ait、notify和notifyAll,不然Java虛擬機(jī)會(huì)生成 IllegalMonitorStateException。

3. 永遠(yuǎn)在while循環(huán)里而不是if語(yǔ)句下使用wait。這樣,循環(huán)會(huì)在線(xiàn)程睡眠前后都檢查wait的條件,并在條件實(shí)際上并未改變的情況下處理喚醒通知。

4. 永遠(yuǎn)在多線(xiàn)程間共享的對(duì)象(在生產(chǎn)者消費(fèi)者模型里即緩沖區(qū)隊(duì)列)上使用wait。

5. 基于前文提及的理由,更傾向用 notifyAll(),而不是 notify()。

怎么在Java中正確使用wait, notify和notifyAll

這是關(guān)于Java里如何使用wait,  notify和notifyAll的所有重點(diǎn)啦。你應(yīng)該只在你知道自己要做什么的情況下使用這些函數(shù),不然Java里還有很多其它的用來(lái)解決同步問(wèn)題的方 案。例如,如果你想使用生產(chǎn)者消費(fèi)者模型的話(huà),你也可以使用BlockingQueue,它會(huì)幫你處理所有的線(xiàn)程安全問(wèn)題和流程控制。如果你想要某一個(gè)線(xiàn) 程等待另一個(gè)線(xiàn)程做出反饋再繼續(xù)運(yùn)行,你也可以使用CycliBarrier或者CountDownLatch。如果你只是想保護(hù)某一個(gè)資源的話(huà),你也可 以使用Semaphore。

關(guān)于“怎么在Java中正確使用wait, notify和notifyAll”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

分享題目:怎么在Java中正確使用wait,notify和notifyAll
網(wǎng)頁(yè)路徑:http://jinyejixie.com/article14/ghopde.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、外貿(mào)網(wǎng)站建設(shè)、面包屑導(dǎo)航、動(dòng)態(tài)網(wǎng)站、微信小程序網(wǎng)頁(yè)設(shè)計(jì)公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁(yè)設(shè)計(jì)公司
浦东新区| 凌云县| 福贡县| 韶山市| 临湘市| 临沂市| 宜黄县| 霍山县| 辛集市| 中山市| 句容市| 平遥县| 五莲县| 古浪县| 巴彦县| 庆云县| 泸定县| 定兴县| 铁岭市| 沂南县| 龙岩市| 荔浦县| 江陵县| 遵义市| 堆龙德庆县| 荥阳市| 芜湖市| 黑山县| 盘山县| 武功县| 东源县| 濮阳市| 西峡县| 苏尼特右旗| 富裕县| 贵州省| 东乡县| 澎湖县| 雅安市| 饶阳县| 炉霍县|