日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

分析java并發中的wait notify notifyAll

瀏覽:160日期:2022-08-10 17:57:35
目錄一、前言二、常見的同步場景2.1、設置一個判斷的標志位2.2、線程的 join 方法2.3、使用閉鎖 CountDownLatch2.4、利用 wait / notify 優化標志位方法三、理解 wait / notify / notifyAll3.1、鎖池3.2、等待池3.3、notify 和 notifyAll 的區別3.3.1、wait()3.3.2、notify()3.3.3、notifyAll()四、生產者與消費者模式五、總結一、前言

java 面試是否有被問到過,sleep 和 wait 方法的區別,關于這個問題其實不用多說,大多數人都能回答出最主要的兩點區別:

sleep 是線程的方法, wait / notify / notifyAll 是 Object 類的方法; sleep 不會釋放當前線程持有的鎖,到時間后程序會繼續執行,wait 會釋放線程持有的鎖并掛起,直到通過 notify 或者 notifyAll 重新獲得鎖。

另外還有一些參數、異常等區別,不細說了。本文重點記錄一下 wait / notify / notifyAll 的相關知識。

二、常見的同步場景

開發中常常遇到這樣的場景:

一個線程執行過程中,需要開啟另外一個子線程去做某個耗時的操作(通過休眠3秒模擬),并且**等待**子線程返回結果,主線程再根據返回的結果繼續往下執行。

這里注意我上面加*兩個字“等待”。如果不需要等待,單純只是對子線程的結果做處理,我們大可注冊回調方法解決問題,此文不再贅述接口回調。

此處場景就是主線程停下來等待子線程執行完畢后,主線程再繼續執行。針對該場景下面給出實現:

2.1、設置一個判斷的標志位

volatile boolean flag = false;public void test(){ //... Thread t1 = new Thread(() -> {try { Thread.sleep(3000); System.out.println('--- 休眠 3 秒');} catch (InterruptedException e) { e.printStackTrace();} finally { flag = true;} }); t1.start(); while(!flag){ } System.out.println('--- work thread run');}

上面的代碼,執行結果:

分析java并發中的wait notify notifyAll

強調一點,聲明標志位的時候,一定注意 volatile 關鍵字不能忘,如果不加該關鍵字修飾,程序可能進入死循環。這是同步中的可見性問題,在 《java 并發——內置鎖》 中有記錄。

顯然,這個實現方案并不好,本來主線程什么也不用做,卻一直在競爭資源,做空循環,性能上不好,所以并不推薦。

2.2、線程的 join 方法

public void test(){ //... Thread t1 = new Thread(() -> {try { Thread.sleep(3000); System.out.println('--- 休眠 3 秒');} catch (InterruptedException e) { e.printStackTrace();} }); t1.start(); try {t1.join(); } catch (InterruptedException e) {e.printStackTrace(); } System.out.println('--- work thread continue');}

上面的代碼,執行結果同上。利用 Thread 類的 join 方法實現了同步,達到了效果,但是 join 方法不能一定保證效果,在不同的 cpu 上,可能呈現出意想不到的結果,所以盡量不要用上述方法。

2.3、使用閉鎖 CountDownLatch

不清楚閉鎖的新同學可以了解下java并發中的線程。

public void test(){ //... final CountDownLatch countDownLatch = new CountDownLatch(1); Thread t1 = new Thread(() -> {try { Thread.sleep(3000); System.out.println('--- 休眠 3 秒');} catch (InterruptedException e) { e.printStackTrace();} finally { countDownLatch.countDown();} }); t1.start(); try {countDownLatch.await(); } catch (InterruptedException e) {e.printStackTrace(); } System.out.println('--- work thread run');}

上面的代碼,執行結果同上。同樣可以實現上述效果,執行結果和上面一樣。該方法推薦使用。

2.4、利用 wait / notify 優化標志位方法

為了方便對比,首先給 2.1 中的循環方法增加一些打印。修改后的代碼如下:

volatile boolean flag = false;public void test() { //... Thread t1 = new Thread(() -> {try { Thread.sleep(3000); System.out.println('--- 休眠 3 秒');} catch (InterruptedException e) { e.printStackTrace();} finally { flag = true;} }); t1.start(); while (!flag) {try { System.out.println('---while-loop---'); Thread.sleep(500);} catch (InterruptedException e) { e.printStackTrace();} } System.out.println('--- work thread run');}

執行結果如下:

分析java并發中的wait notify notifyAll

事實證明,while 循環確實一直在執行。

為了使該線程再不需要執行的時候不搶占資源,我們可以利用 wait 方法將其掛起,在需要它執行的時候,再利用 notify 方法將其喚醒。這樣達到優化的目的,優化后的代碼如下:

volatile boolean flag = false;public void test() { //... final Object obj = new Object(); Thread t1 = new Thread(() -> {synchronized (obj) { try {Thread.sleep(3000);System.out.println('--- 休眠 3 秒'); } catch (InterruptedException e) {e.printStackTrace(); } finally {flag = true; } obj.notify();} }); t1.start(); synchronized (obj) {while (!flag) { try {System.out.println('---while-loop---');Thread.sleep(500);obj.wait(); } catch (InterruptedException e) {e.printStackTrace(); }} } System.out.println('--- work thread run');}

執行結果:

分析java并發中的wait notify notifyAll

結果證明,優化后的程序,循環只執行了一次。

三、理解 wait / notify / notifyAll

在Java中,每個對象都有兩個池,鎖(monitor)池和等待池

3.1、鎖池

鎖池:假設線程A已經擁有了某個對象的鎖,而其它的線程想要調用這個對象的某個synchronized方法(或者synchronized塊),由于這些線程在進入對象的synchronized方法之前必須先獲得該對象的鎖的擁有權,但是該對象的鎖目前正被線程A擁有,所以這些線程就進入了該對象的鎖池中。

3.2、等待池

等待池:假設一個線程A調用了某個對象的wait()方法,線程A就會釋放該對象的鎖(因為wait()方法必須出現在synchronized中,這樣自然在執行wait()方法之前線程A就已經擁有了該對象的鎖),同時線程A就進入到了該對象的等待池中。如果另外的一個線程調用了相同對象的notifyAll()方法,那么處于該對象的等待池中的線程就會全部進入該對象的鎖池中,準備爭奪鎖的擁有權。如果另外的一個線程調用了相同對象的notify()方法,那么僅僅有一個處于該對象的等待池中的線程(隨機)會進入該對象的鎖池.

3.3、notify 和 notifyAll 的區別3.3.1、wait()

public final void wait() throws InterruptedException,IllegalMonitorStateException該方法用來將當前線程置入休眠狀態,直到接到通知或被中斷為止。在調用 wait()之前,線程必須要獲得該對象的對象級別鎖,即只能在同步方法或同步塊中調用 wait()方法。進入 wait()方法后,當前線程釋放鎖。在從 wait()返回前,線程與其他線程競爭重新獲得鎖。如果調用 wait()時,沒有持有適當的鎖,則拋出 IllegalMonitorStateException,它是 RuntimeException 的一個子類,因此,不需要 try-catch 結

3.3.2、notify()

public final native void notify() throws IllegalMonitorStateException該方法也要在同步方法或同步塊中調用,即在調用前,線程也必須要獲得該對象的對象級別鎖,的如果調用 notify()時沒有持有適當的鎖,也會拋出 IllegalMonitorStateException。該方法用來通知那些可能等待該對象的對象鎖的其他線程。如果有多個線程等待,則線程規劃器任意挑選出其中一個 wait()狀態的線程來發出通知,并使它等待獲取該對象的對象鎖(notify 后,當前線程不會馬上釋放該對象鎖,wait 所在的線程并不能馬上獲取該對象鎖,要等到程序退出 synchronized 代碼塊后,當前線程才會釋放鎖,wait所在的線程也才可以獲取該對象鎖),但不驚動其他同樣在等待被該對象notify的線程們。當第一個獲得了該對象鎖的 wait 線程運行完畢以后,它會釋放掉該對象鎖,此時如果該對象沒有再次使用 notify 語句,則即便該對象已經空閑,其他 wait 狀態等待的線程由于沒有得到該對象的通知,會繼續阻塞在 wait 狀態,直到這個對象發出一個 notify 或 notifyAll。這里需要注意:它們等待的是被 notify 或 notifyAll,而不是鎖。這與下面的 notifyAll()方法執行后的情況不同。

3.3.3、notifyAll()

public final native void notifyAll() throws IllegalMonitorStateException

該方法與 notify ()方法的工作方式相同,重要的一點差異是:

notifyAll 使所有原來在該對象上 wait 的線程統統退出 wait 的狀態(即全部被喚醒,不再等待 notify 或 notifyAll,但由于此時還沒有獲取到該對象鎖,因此還不能繼續往下執行),變成等待獲取該對象上的鎖,一旦該對象鎖被釋放(notifyAll 線程退出調用了 notifyAll 的 synchronized 代碼塊的時候),他們就會去競爭。如果其中一個線程獲得了該對象鎖,它就會繼續往下執行,在它退出 synchronized 代碼塊,釋放鎖后,其他的已經被喚醒的線程將會繼續競爭獲取該鎖,一直進行下去,直到所有被喚醒的線程都執行完畢。

四、生產者與消費者模式

生產者與消費者問題是并發編程里面的經典問題。接下來說說利用wait()和notify()來實現生產者和消費者并發問題:顯然要保證生產者和消費者并發運行不出亂,主要要解決:當生產者線程的緩存區為滿的時候,就應該調用wait()來停止生產者繼續生產,而當生產者滿的緩沖區被消費者消費掉一塊時,則應該調用notify()喚醒生產者,通知他可以繼續生產;同樣,對于消費者,當消費者線程的緩存區為空的時候,就應該調用wait()停掉消費者線程繼續消費,而當生產者又生產了一個時就應該調用notify()來喚醒消費者線程通知他可以繼續消費了。

下面是一個簡單的代碼實現:

package com.sharpcj;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Test { public static void main(String[] args) {Reposity reposity = new Reposity(600);ExecutorService threadPool = Executors.newCachedThreadPool();for(int i = 0; i < 10; i++){ threadPool.submit(new Producer(reposity));}for(int i = 0; i < 10; i++){ threadPool.submit(new Consumer(reposity));}threadPool.shutdown(); }}class Reposity { private static final int MAX_NUM = 2000; private int currentNum; private final Object obj = new Object(); public Reposity(int currentNum) {this.currentNum = currentNum; } public void in(int inNum) {synchronized (obj) { while (currentNum + inNum > MAX_NUM) {try { System.out.println('入貨量 ' + inNum + ' 線程 ' + Thread.currentThread().getId() + '被掛起...'); obj.wait();} catch (InterruptedException e) { e.printStackTrace();} } try {Thread.sleep(200); } catch (InterruptedException e) {e.printStackTrace(); } currentNum += inNum; System.out.println('線程: ' + Thread.currentThread().getId() + ',入貨:inNum = [' + inNum + '], currentNum = [' + currentNum + ']'); obj.notifyAll();} } public void out(int outNum) {synchronized (obj) { while (currentNum < outNum) {try { System.out.println('出貨量 ' + outNum + ' 線程 ' + Thread.currentThread().getId() + '被掛起...'); obj.wait();} catch (InterruptedException e) { e.printStackTrace();} } try {Thread.sleep(200); } catch (InterruptedException e) {e.printStackTrace(); } currentNum -= outNum; System.out.println('線程: ' + Thread.currentThread().getId() + ',出貨:outNum = [' + outNum + '], currentNum = [' + currentNum + ']'); obj.notifyAll();} }}class Producer implements Runnable { private Reposity reposity; public Producer(Reposity reposity) {this.reposity = reposity; } @Override public void run() {reposity.in(200); }}class Consumer implements Runnable { private Reposity reposity; public Consumer(Reposity reposity) {this.reposity = reposity; } @Override public void run() {reposity.out(200); }}

執行結果:

分析java并發中的wait notify notifyAll

五、總結

1.調用wait方法和notify、notifyAll方法前必須獲得對象鎖,也就是必須寫在synchronized(鎖對象){......}代碼塊中。

2.當線程調用了wait方法后就釋放了對象鎖,否則其他線程無法獲得對象鎖。

3.當調用 wait() 方法后,線程必須再次獲得對象鎖后才能繼續執行。

4.如果另外兩個線程都在 wait,則正在執行的線程調用notify方法只能喚醒一個正在wait的線程(公平競爭,由JVM決定)。

5.當使用notifyAll方法后,所有wait狀態的線程都會被喚醒,但是只有一個線程能獲得鎖對象,必須執行完while(condition){this.wait();}后才釋放對象鎖。其余的需要等待該獲得對象鎖的線程執行完釋放對象鎖后才能繼續執行。

6.當某個線程調用notifyAll方法后,雖然其他線程被喚醒了,但是該線程依然持有著對象鎖,必須等該同步代碼塊執行完(右大括號結束)后才算正式釋放了鎖對象,另外兩個線程才有機會執行。

7.第5點中說明, wait 方法的調用前的條件判斷需放在循環中,否則可能出現邏輯錯誤。另外,根據程序邏輯合理使用 wait 即 notify 方法,避免如先執行 notify ,后執行 wait 方法,線程一直掛起之類的錯誤。

以上就是分析java并發中的wait notify notifyAll的詳細內容,更多關于java并發wait notify notifyAll的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产视频欧美| 另类国产ts人妖高潮视频| 欧美国产91| 欧美在线影院| 日本亚洲不卡| 国产亚洲精品美女久久| 国产精品一区二区三区美女 | 亚洲成人精品| 一区免费视频| 蜜桃精品在线| 日本 国产 欧美色综合| 奇米亚洲欧美| 欧美sss在线视频| 成人久久久久| 野花国产精品入口| 在线观看亚洲精品福利片| 国产在线观看91一区二区三区 | 久久国产生活片100| 日韩高清成人在线| 欧美日韩精品一区二区三区视频| 日韩二区三区四区| 美女久久久久久| 国产精品啊啊啊| 久久久久中文| 激情五月色综合国产精品| 影音先锋久久| 亚洲2区在线| 久久国产成人午夜av影院宅| 国产主播一区| 欧美精品97| 亚洲欧洲高清| 97久久亚洲| 国产精品久久久久久久久免费高清 | 国产高清精品二区| 欧美精品资源| 一级成人国产| 国产欧美亚洲一区| 成人午夜网址| 午夜久久免费观看| 日韩欧美中文字幕一区二区三区| 国产欧美日韩一级| 亚洲天堂一区二区| 中文字幕乱码亚洲无线精品一区| 中文视频一区| 麻豆精品久久| 国产综合精品| 日本少妇精品亚洲第一区| 理论片午夜视频在线观看| 亚洲激情中文| 日本亚洲欧洲无免费码在线| 精品中文字幕一区二区三区四区| 日韩毛片一区| 福利一区二区三区视频在线观看| 尤物在线精品| 国产精品嫩模av在线| 日本国产精品| 日韩高清在线不卡| 国产精品高颜值在线观看| 久久国产成人午夜av影院宅| 91欧美日韩在线| 久久精品国产亚洲夜色av网站| 日韩国产在线不卡视频| 久久久久美女| 国产日韩欧美中文在线| 欧美午夜精彩| 国产精品男女| 99热精品在线| 成人在线视频区| 蜜臀av亚洲一区中文字幕| 欧美xxxx中国| 欧美精品97| 国产婷婷精品| 国产成年精品| 午夜免费一区| 美女免费视频一区| 一区二区三区国产盗摄| 国产一区二区三区黄网站| 石原莉奈在线亚洲二区| 高清一区二区三区av| 蜜臀av性久久久久蜜臀aⅴ四虎| 精品视频在线观看网站| 亚洲欧洲日韩精品在线| 久久精品播放| 国产一区二区三区亚洲| 欧美一区自拍| 巨乳诱惑日韩免费av| 免费污视频在线一区| 欧美精品国产一区| 欧洲av一区二区| 免费看久久久| 香蕉久久一区| 亚洲一级影院| 国产在线看片免费视频在线观看| 69堂精品视频在线播放| 亚洲欧美久久| 亚洲a在线视频| 欧美久久天堂| 久久精品人人| 国产精品手机在线播放| 亚洲精品伊人| 人人精品人人爱| 国产精品日韩久久久| 亚洲91视频| 精品久久久中文字幕| 国产亚洲一区二区三区啪| 久久福利毛片| 日韩高清中文字幕一区二区| 国产福利一区二区三区在线播放| 日韩影片在线观看| 在线一区免费观看| 免费成人网www| 丁香六月综合| 丁香婷婷久久| 麻豆国产欧美一区二区三区 | 在线亚洲观看| 精品欧美激情在线观看| 99久久视频| 成人国产精品久久| 精品网站aaa| 久久精品天堂| 久久三级毛片| 久久一区亚洲| 国产激情精品一区二区三区| 国产精选久久| 国产极品嫩模在线观看91精品| 青青国产精品| 青青青国产精品| 美女91精品| 一区二区三区四区在线看| 日韩成人亚洲| 国产在线日韩| 亚洲综合二区| 亚洲一卡久久| 少妇精品久久久一区二区| 少妇精品久久久| 91精品视频一区二区| 国产毛片一区二区三区| 91成人在线网站| 国产精品高清一区二区| 久久一区视频| 日韩精品麻豆| 尹人成人综合网| 亚洲精品乱码久久久久久蜜桃麻豆| 亚洲精品九九| 久久国产人妖系列| 国内一区二区三区| 99成人在线视频| 欧美影院三区| 亚洲精品伦理| 国产福利一区二区精品秒拍| 亚洲国产成人二区| 婷婷色综合网| 天堂俺去俺来也www久久婷婷| 国产欧美日韩影院| 国产一区二区三区亚洲| 999国产精品| 免费人成黄页网站在线一区二区| 亚洲综合五月| 国产精品2023| 91精品蜜臀一区二区三区在线| 国产高清不卡| 国产综合欧美| 免费久久精品视频| 国产精品22p| 国产专区一区| 日韩不卡一区二区三区| 激情综合五月| 欧美日韩在线播放视频| 亚洲一二av| 国产一区丝袜| 丝袜a∨在线一区二区三区不卡| 日韩三区四区| sm捆绑调教国产免费网站在线观看| 99riav国产精品| 久久成人av| 91久久在线| 麻豆精品av| 米奇777超碰欧美日韩亚洲| 欧美日一区二区三区在线观看国产免 | 亚洲综合图色| 超碰99在线| 丝袜美腿亚洲色图| 精品三级久久久| 日韩精品一二三四| 国产精品99一区二区三| 蜜臀久久久久久久| 国产极品久久久久久久久波多结野 | 日韩成人一级| 99热国内精品| 国产精品v亚洲精品v日韩精品| 99久精品视频在线观看视频| 欧美在线看片| 亚洲少妇诱惑| 福利片在线一区二区| 免费观看日韩电影| 女生影院久久| 国产精品一区二区av日韩在线| 午夜视频精品| 欧美aⅴ一区二区三区视频| 中日韩男男gay无套|