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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

生产者与消费者案例-虚假唤醒

發(fā)布時(shí)間:2023/12/31 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 生产者与消费者案例-虚假唤醒 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

以下是一個(gè)案例,有一個(gè)店員,負(fù)責(zé)進(jìn)貨和賣貨。進(jìn)貨生產(chǎn),賣貨消費(fèi)。

當(dāng)商品超過10件,生產(chǎn)等待,消費(fèi)繼續(xù),當(dāng)少于0件,消費(fèi)等待,消費(fèi)繼續(xù)。

正常代碼如下:

package com.atguigu.juc;/** 生產(chǎn)者和消費(fèi)者案例*/ public class TestProductorAndConsumer {public static void main(String[] args) {Clerk clerk = new Clerk();Productor pro = new Productor(clerk);Consumer cus = new Consumer(clerk);new Thread(pro, "生產(chǎn)者 A").start();new Thread(cus, "消費(fèi)者 B").start();} } //店員 class Clerk {private int product = 0;//進(jìn)貨public synchronized void get(){//循環(huán)次數(shù):0if(product >= 10){System.out.println("產(chǎn)品已滿!");try {this.wait();} catch (InterruptedException e) {}}System.out.println(Thread.currentThread().getName() + " : " + ++product);this.notifyAll();}//賣貨public synchronized void sale(){//product = 0; 循環(huán)次數(shù):0if(product <= 0){System.out.println("缺貨!");try {this.wait();} catch (InterruptedException e) {}}System.out.println(Thread.currentThread().getName() + " : " + --product);this.notifyAll();} }//生產(chǎn)者 class Productor implements Runnable{private Clerk clerk;public Productor(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {try {Thread.sleep(200);} catch (InterruptedException e) {}clerk.get();}} }//消費(fèi)者 class Consumer implements Runnable{private Clerk clerk;public Consumer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {clerk.sale();}} }

運(yùn)行結(jié)果:

很和諧沒問題!,生產(chǎn)者每次生產(chǎn)完就等待一下,導(dǎo)致消費(fèi)者搶到資源,這樣導(dǎo)致:0,1輪替。

但是,如果此時(shí)再假如一個(gè)生產(chǎn)者和消費(fèi)者:

public class TestProductorAndConsumer {public static void main(String[] args) {Clerk clerk = new Clerk();Productor pro = new Productor(clerk);Consumer cus = new Consumer(clerk);new Thread(pro, "生產(chǎn)者 A").start();new Thread(cus, "消費(fèi)者 B").start();new Thread(pro, "生產(chǎn)者 C").start();new Thread(cus, "消費(fèi)者 D").start();} }

此時(shí)運(yùn)行結(jié)果:

?

可以看到,非常離譜!生產(chǎn)者數(shù)量為負(fù)數(shù),并且一直沒有停止的樣子。

分析:

假如最開始是缺貨狀態(tài),消費(fèi)者B和D進(jìn)入都是進(jìn)入等待的,此時(shí)一個(gè)生產(chǎn)者搶到資源,進(jìn)行生產(chǎn),完事生產(chǎn)了一件,

兩個(gè)消費(fèi)者同時(shí)喚醒,喚醒了之后,每個(gè)消費(fèi)者都繼續(xù)下面代碼,也就是wait下面的--product,導(dǎo)致數(shù)量為負(fù)數(shù)。

這個(gè)時(shí)候兩個(gè)消費(fèi)者再次進(jìn)入當(dāng)然還是等待,一個(gè)生產(chǎn)者再次進(jìn)入,當(dāng)然效果和上面一樣,再次數(shù)量在-1的基礎(chǔ)上,-1,-2。

?

這種現(xiàn)象叫做虛假喚醒。

?

為了解決這個(gè),其實(shí)JDK中已經(jīng)說明了,對于wait方法的使用,必須始終放在while循環(huán)中。

每次線程被喚醒之后都得重新進(jìn)入循環(huán),而不是直接執(zhí)行下面的--或者++操作。

修改如下:

把上面的if換成while即可:

package com.atguigu.juc;/** 生產(chǎn)者和消費(fèi)者案例*/ public class TestProductorAndConsumer {public static void main(String[] args) {Clerk clerk = new Clerk();Productor pro = new Productor(clerk);Consumer cus = new Consumer(clerk);new Thread(pro, "生產(chǎn)者 A").start();new Thread(cus, "消費(fèi)者 B").start();new Thread(pro, "生產(chǎn)者 C").start();new Thread(cus, "消費(fèi)者 D").start();} } //店員 class Clerk {private int product = 0;//進(jìn)貨public synchronized void get(){//循環(huán)次數(shù):0while(product >= 10){//為了避免虛假喚醒問題,應(yīng)該總是使用在循環(huán)中System.out.println("產(chǎn)品已滿!");try {this.wait();} catch (InterruptedException e) {}}System.out.println(Thread.currentThread().getName() + " : " + ++product);this.notifyAll();}//賣貨public synchronized void sale(){//product = 0; 循環(huán)次數(shù):0while(product <= 0){System.out.println("缺貨!");try {this.wait();} catch (InterruptedException e) {}}System.out.println(Thread.currentThread().getName() + " : " + --product);this.notifyAll();} }//生產(chǎn)者 class Productor implements Runnable{private Clerk clerk;public Productor(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {try {Thread.sleep(200);} catch (InterruptedException e) {}clerk.get();}} }//消費(fèi)者 class Consumer implements Runnable{private Clerk clerk;public Consumer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {clerk.sale();}} }

?

?

總結(jié)

以上是生活随笔為你收集整理的生产者与消费者案例-虚假唤醒的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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