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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

单线程下的生产者--消费者模式详解,wait和sleep的区别

發(fā)布時(shí)間:2025/3/19 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单线程下的生产者--消费者模式详解,wait和sleep的区别 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1. 單線程下的生產(chǎn)者--消費(fèi)者模式

1.1 該模式下,一個(gè)線程生產(chǎn)數(shù)據(jù),另一個(gè)線程處理數(shù)據(jù)。當(dāng)數(shù)據(jù)還沒被處理,那么生產(chǎn)數(shù)據(jù)的線程進(jìn)入等待狀態(tài);如果數(shù)據(jù)還沒生產(chǎn),那么處理數(shù)據(jù)的線程進(jìn)入等待狀態(tài),代碼及運(yùn)行結(jié)果如下。

// 生產(chǎn)者 class Producer extends Thread{private final List<Object> lst;public Producer(List<Object> lst){this.lst = lst;}@Overridepublic void run() {while(true){synchronized (lst){if(lst.size() > 0){try {lst.wait();} catch (InterruptedException e) {e.printStackTrace();}}lst.add(new Object());System.out.println("生產(chǎn)者:" + lst.size());lst.notify();}}} }// 消費(fèi)者 class Consumer extends Thread{private final List<Object> lst;public Consumer(List<Object> lst){this.lst = lst;}@Overridepublic void run() {while(true){synchronized (lst){if(lst.size() == 0){try {lst.wait();} catch (InterruptedException e) {e.printStackTrace();}}lst.remove(0);System.out.println("消費(fèi)者:" + lst.size());lst.notify();}}} }

1.2 功能分析。生產(chǎn)者和消費(fèi)者共享同一個(gè)ArrayList對象,生產(chǎn)者往ArrayList放數(shù)據(jù),消費(fèi)者刪除數(shù)據(jù)。初始時(shí),ArrayList里沒有數(shù)據(jù),如果消費(fèi)者先操作ArrayList對象,判斷ArrayList對象沒有數(shù)據(jù)后,執(zhí)行wait方法進(jìn)入等待狀態(tài)并釋放ArrayList對象鎖;此時(shí)生產(chǎn)者得到該鎖,判斷ArrayList沒有數(shù)據(jù)后,往里面添加一個(gè)數(shù)據(jù),并調(diào)用notify方法喚醒進(jìn)入等待狀態(tài)的消費(fèi)者。如果此時(shí)生產(chǎn)者又搶到ArrayList對象鎖,那么判斷ArrayList對象有數(shù)據(jù)后,會進(jìn)入等待狀態(tài),前面被喚醒的消費(fèi)者來消費(fèi)并喚醒剛進(jìn)入等待的生產(chǎn)者,后面一直如此循環(huán)....

2. wait和notify方法

2.1 wait方法,執(zhí)行該方法的線程會進(jìn)入阻塞狀態(tài),而不是可運(yùn)行狀態(tài),所以不會去搶奪CPU時(shí)間片;同時(shí)會釋放正在占用的對象鎖

2.2 關(guān)于執(zhí)行wait方法的線程是否會搶奪CPU時(shí)間片,下面通過資源監(jiān)視器來證明一下。當(dāng)我沒有運(yùn)行java程序時(shí),CPU的利用率是6%左右,如下圖。

當(dāng)java創(chuàng)建10個(gè)線程,一個(gè)while循環(huán),沒有任何邏輯代碼,CPU利用率達(dá)到了100%。

此時(shí)我們在while循環(huán)中寫上wait方法,我們可以發(fā)現(xiàn),CPU利用率只有剛創(chuàng)建線程時(shí)會有短暫的升高,后面線程執(zhí)行了wait方法進(jìn)入等待狀態(tài)并沒有導(dǎo)致CPU利用率升高,所以執(zhí)行wait方法的線程不會搶奪CPU時(shí)間片。

同理,sleep方法也并不會搶奪CPU時(shí)間片,但sleep方法不釋放鎖

2.3 wait和sleep的區(qū)別

① wait是Object的方法,sleep是Thread的方法。

② wait會釋放占有的鎖,但sleep不會釋放鎖。

③ wait必須用在同步代碼塊或同步方法中,sleep不需要。

④ 它們都不會去搶奪CPU時(shí)間片

⑤ 調(diào)用wait方法時(shí)線程會進(jìn)入waiting狀態(tài);而調(diào)用sleep方法時(shí)線程會進(jìn)入timed_waiting狀態(tài);線程等待synchronized同步代碼塊或同步方法時(shí)進(jìn)入blocked狀態(tài)。

2.4?notify方法:喚醒等待狀態(tài)的線程,將線程從阻塞狀態(tài)變?yōu)榭蛇\(yùn)行狀態(tài),搶到CPU時(shí)間片再執(zhí)行;同時(shí)還要占有鎖才能執(zhí)行

3. 多線程下的生產(chǎn)者消費(fèi)者模式

3.1 我們先使用第一節(jié)的消費(fèi)者和生產(chǎn)者代碼,分別創(chuàng)建兩個(gè)消費(fèi)者和兩個(gè)生產(chǎn)者,得到運(yùn)行結(jié)果如下。

3.2 出現(xiàn)一直生產(chǎn)的情況的原因:生產(chǎn)了數(shù)據(jù)的生產(chǎn)者會喚醒一個(gè)正在等待狀態(tài)的線程,如果此時(shí)喚醒的是另一個(gè)生產(chǎn)者,那么又會生產(chǎn)數(shù)據(jù),然后該生產(chǎn)者會有喚醒一個(gè)等待狀態(tài)的線程,如果此時(shí)喚醒的又是生產(chǎn)者,那么循環(huán)往復(fù),就會一直生產(chǎn)數(shù)據(jù)....

3.3 既然出現(xiàn)一直生產(chǎn)的情況,是因?yàn)楸粏拘阎苯由a(chǎn)數(shù)據(jù),那么就在被喚醒后仍然判斷一下是否有數(shù)據(jù),如果有,再進(jìn)入等待狀態(tài),代碼如下。

3.4 運(yùn)行后,會出現(xiàn)卡死情況,原因:當(dāng)沒有數(shù)據(jù)時(shí),兩個(gè)消費(fèi)者會進(jìn)入等待狀態(tài),此時(shí)如果一個(gè)生產(chǎn)者占有鎖,它會生產(chǎn)一個(gè)數(shù)據(jù),如果此時(shí)喚醒的是一個(gè)等待狀態(tài)的生產(chǎn)者,那么生產(chǎn)者還是進(jìn)入等待,等到自己再次搶到鎖,依然因?yàn)橛袛?shù)據(jù)而進(jìn)入等待狀態(tài),也就出現(xiàn)了卡死現(xiàn)象。

3.5 既然是因?yàn)槎歼M(jìn)入了等待狀態(tài),那么每次都用notifyAll方法,把所有等待狀態(tài)的線程都喚醒,就不會出現(xiàn)卡死現(xiàn)象了,最終代碼如下。

import java.util.ArrayList; import java.util.List;public class WaitNotifyTest {public static void main(String[] args) {List<Object> lst = new ArrayList<>();Producer pro = new Producer(lst);Consumer con = new Consumer(lst);pro.start();con.start();new Producer(lst).start();new Consumer(lst).start();} }class Producer extends Thread{private final List<Object> lst;public Producer(List<Object> lst){this.lst = lst;}@Overridepublic void run() {while(true){synchronized (lst){while(lst.size() > 0){try {lst.wait();} catch (InterruptedException e) {e.printStackTrace();}}lst.add(new Object());System.out.println("生產(chǎn)者:" + lst.size());lst.notifyAll();}}} }class Consumer extends Thread{private final List<Object> lst;public Consumer(List<Object> lst){this.lst = lst;}@Overridepublic void run() {while(true){synchronized (lst){while(lst.size() == 0){try {lst.wait();} catch (InterruptedException e) {e.printStackTrace();}}lst.remove(0);System.out.println("消費(fèi)者:" + lst.size());lst.notifyAll();}}} }

4. 通過鉤子程序捕獲程序退出以及setUncaughtExceptionHandler方法捕獲線程拋出的運(yùn)行時(shí)異常

總結(jié)

以上是生活随笔為你收集整理的单线程下的生产者--消费者模式详解,wait和sleep的区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。