亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

搜索
首頁 > web前端 > js教程 > 正文

java多線程之并發(fā)協(xié)作生產(chǎn)者消費(fèi)者設(shè)計(jì)模式

伊謝爾倫
發(fā)布: 2016-11-21 13:31:37
原創(chuàng)
1960人瀏覽過

 兩個線程一個生產(chǎn)者個一個消費(fèi)者

  需求情景

  兩個線程,一個負(fù)責(zé)生產(chǎn),一個負(fù)責(zé)消費(fèi),生產(chǎn)者生產(chǎn)一個,消費(fèi)者消費(fèi)一個

  涉及問題

  同步問題:如何保證同一資源被多個線程并發(fā)訪問時的完整性。常用的同步方法是采用標(biāo)記或加鎖機(jī)制

  wait() / nofity() 方法是基類object的兩個方法,也就意味著所有java類都會擁有這兩個方法,這樣,我們就可以為任何對象實(shí)現(xiàn)同步機(jī)制。

  wait()方法:當(dāng)緩沖區(qū)已滿/空時,生產(chǎn)者/消費(fèi)者線程停止自己的執(zhí)行,放棄鎖,使自己處于等等狀態(tài),讓其他線程執(zhí)行。

  notify()方法:當(dāng)生產(chǎn)者/消費(fèi)者向緩沖區(qū)放入/取出一個產(chǎn)品時,向其他等待的線程發(fā)出可執(zhí)行的通知,同時放棄鎖,使自己處于等待狀態(tài)。

  代碼實(shí)現(xiàn)(共三個類和一個main方法的測試類)

  Resource.java
  /**
  * Created by yuandl on 2016-10-11./**
  * 資源
  */
  public class Resource {
  /*資源序號*/
  private int number = 0;
  /*資源標(biāo)記*/
  private boolean flag = false;
  /**
  * 生產(chǎn)資源
  */
  public synchronized void create() {
  if (flag) {//先判斷標(biāo)記是否已經(jīng)生產(chǎn)了,如果已經(jīng)生產(chǎn),等待消費(fèi);
  try {
  wait();//讓生產(chǎn)線程等待
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  number++;//生產(chǎn)一個
  System.out.println(Thread.currentThread().getName() + "生產(chǎn)者------------" + number);
  flag = true;//將資源標(biāo)記為已經(jīng)生產(chǎn)
  notify();//喚醒在等待操作資源的線程(隊(duì)列)
  }
  /**
  * 消費(fèi)資源
  */
  public synchronized void destroy() {
  if (!flag) {
  try {
  wait();
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  System.out.println(Thread.currentThread().getName() + "消費(fèi)者****" + number);
  flag = false;
  notify();
  }
 }
登錄后復(fù)制

  Producer.java 

  /**
  * Created by yuandl on 2016-10-11.
  *
  /**
  * 生產(chǎn)者
  */
  public class Producer implements Runnable {
  private Resource resource;
  public Producer(Resource resource) {
  this.resource = resource;
  }
  @Override
  public void run() {
  while (true) {
  try {
  Thread.sleep(10);
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  resource.create();
  }
  }
  }
登錄后復(fù)制

 Consumer.java

 /**
  * 消費(fèi)者
  */
  public class Consumer implements Runnable {
  private Resource resource;
  public Consumer(Resource resource) {
  this.resource = resource;
  }
  @Override
  public void run() {
  while (true) {
  try {
  Thread.sleep(10);
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  resource.destroy();
  }
  }
  }
登錄后復(fù)制

 ProducerConsumerTest.java

  /**
  * Created by yuandl on 2016-10-11.
  */
  public class ProducerConsumerTest {
  public static void main(String args[]) {
  Resource resource = new Resource();
  new Thread(new Producer(resource)).start();//生產(chǎn)者線程
  new Thread(new Consumer(resource)).start();//消費(fèi)者線程
  }
  }
登錄后復(fù)制

打印結(jié)果

立即學(xué)習(xí)Java免費(fèi)學(xué)習(xí)筆記(深入)”;

Thread-0生產(chǎn)者------------1
 Thread-1消費(fèi)者****1
  Thread-0生產(chǎn)者------------2
  Thread-1消費(fèi)者****2
  Thread-0生產(chǎn)者------------3
  Thread-1消費(fèi)者****3
  Thread-0生產(chǎn)者------------4
  Thread-1消費(fèi)者****4
  Thread-0生產(chǎn)者------------5
  Thread-1消費(fèi)者****5
  Thread-0生產(chǎn)者------------6
  Thread-1消費(fèi)者****6
  Thread-0生產(chǎn)者------------7
  Thread-1消費(fèi)者****7
  Thread-0生產(chǎn)者------------8
  Thread-1消費(fèi)者****8
  Thread-0生產(chǎn)者------------9
  Thread-1消費(fèi)者****9
  Thread-0生產(chǎn)者------------10
  Thread-1消費(fèi)者****10
登錄后復(fù)制

以上打印結(jié)果可以看出沒有任何問題


  多個線程,多個生產(chǎn)者和多個消費(fèi)者的問題

  需求情景

  四個線程,兩個個負(fù)責(zé)生產(chǎn),兩個個負(fù)責(zé)消費(fèi),生產(chǎn)者生產(chǎn)一個,消費(fèi)者消費(fèi)一個

  涉及問題

  notifyAll()方法:當(dāng)生產(chǎn)者/消費(fèi)者向緩沖區(qū)放入/取出一個產(chǎn)品時,向其他等待的所有線程發(fā)出可執(zhí)行的通知,同時放棄鎖,使自己處于等待狀態(tài)。

  再次測試代碼

 

 ProducerConsumerTest.java
  /**
  * Created by yuandl on 2016-10-11.
  */
  public class ProducerConsumerTest {
  public static void main(String args[]) {
  Resource resource = new Resource();
  new Thread(new Consumer(resource)).start();//生產(chǎn)者線程
  new Thread(new Consumer(resource)).start();//生產(chǎn)者線程
  new Thread(new Producer(resource)).start();//消費(fèi)者線程
  new Thread(new Producer(resource)).start();//消費(fèi)者線程
  }
  }
登錄后復(fù)制

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

歌者PPT
歌者PPT

歌者PPT,AI 寫 PPT 永久免費(fèi)

歌者PPT197
查看詳情 歌者PPT
  Thread-0生產(chǎn)者------------100
  Thread-3消費(fèi)者****100
  Thread-0生產(chǎn)者------------101
  Thread-3消費(fèi)者****101
  Thread-2消費(fèi)者****101
  Thread-1生產(chǎn)者------------102
  Thread-3消費(fèi)者****102
  Thread-0生產(chǎn)者------------103
  Thread-2消費(fèi)者****103
  Thread-1生產(chǎn)者------------104
  Thread-3消費(fèi)者****104
  Thread-1生產(chǎn)者------------105
  Thread-0生產(chǎn)者------------106
  Thread-2消費(fèi)者****106
  Thread-1生產(chǎn)者------------107
  Thread-3消費(fèi)者****107
  Thread-0生產(chǎn)者------------108
  Thread-2消費(fèi)者****108
  Thread-0生產(chǎn)者------------109
  Thread-2消費(fèi)者****109
  Thread-1生產(chǎn)者------------110
  Thread-3消費(fèi)者****110
登錄后復(fù)制

 通過以上打印結(jié)果發(fā)現(xiàn)問題


  101生產(chǎn)了一次,消費(fèi)了兩次

  105生產(chǎn)了,而沒有消費(fèi)

  原因分析

  當(dāng)兩個線程同時操作生產(chǎn)者生產(chǎn)或者消費(fèi)者消費(fèi)時,如果有生產(chǎn)者或者的兩個線程都wait()時,再次notify(),由于其中一個線程已經(jīng)改變了標(biāo)記而另外一個線程再次往下直接執(zhí)行的時候沒有判斷標(biāo)記而導(dǎo)致的。

  if判斷標(biāo)記,只有一次,會導(dǎo)致不該運(yùn)行的線程運(yùn)行了。出現(xiàn)了數(shù)據(jù)錯誤的情況。

  解決方案

  while判斷標(biāo)記,解決了線程獲取執(zhí)行權(quán)后,是否要運(yùn)行!也就是每次wait()后再notify()時先再次判斷標(biāo)記

  代碼改進(jìn)(Resource中的if->while)

  Resource.java

 
 /**
  * Created by yuandl on 2016-10-11./**
  * 資源
  */
  public class Resource {
  /*資源序號*/
  private int number = 0;
  /*資源標(biāo)記*/
  private boolean flag = false;
  /**
  * 生產(chǎn)資源
  */
  public synchronized void create() {
  while (flag) {//先判斷標(biāo)記是否已經(jīng)生產(chǎn)了,如果已經(jīng)生產(chǎn),等待消費(fèi);
  try {
  wait();//讓生產(chǎn)線程等待
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  number++;//生產(chǎn)一個
  System.out.println(Thread.currentThread().getName() + "生產(chǎn)者------------" + number);
  flag = true;//將資源標(biāo)記為已經(jīng)生產(chǎn)
  notify();//喚醒在等待操作資源的線程(隊(duì)列)
  }
  /**
  * 消費(fèi)資源
  */
  public synchronized void destroy() {
  while (!flag) {
  try {
  wait();
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  System.out.println(Thread.currentThread().getName() + "消費(fèi)者****" + number);
  flag = false;
  notify();
  }
  }
登錄后復(fù)制

再次發(fā)現(xiàn)問題


  打印到某個值比如生產(chǎn)完74,程序運(yùn)行卡死了,好像鎖死了一樣。

  原因分析

  notify:只能喚醒一個線程,如果本方喚醒了本方,沒有意義。而且while判斷標(biāo)記+notify會導(dǎo)致”死鎖”。

  解決方案

  notifyAll解決了本方線程一定會喚醒對方線程的問題。

  最后代碼改進(jìn)(Resource中的notify()->notifyAll())

  Resource.java 

 /**
  * Created by yuandl on 2016-10-11./**
  * 資源
  */
  public class Resource {
  /*資源序號*/
  private int number = 0;
  /*資源標(biāo)記*/
  private boolean flag = false;
  /**
  * 生產(chǎn)資源
  */
  public synchronized void create() {
  while (flag) {//先判斷標(biāo)記是否已經(jīng)生產(chǎn)了,如果已經(jīng)生產(chǎn),等待消費(fèi);
  try {
  wait();//讓生產(chǎn)線程等待
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  number++;//生產(chǎn)一個
  System.out.println(Thread.currentThread().getName() + "生產(chǎn)者------------" + number);
  flag = true;//將資源標(biāo)記為已經(jīng)生產(chǎn)
  notifyAll();//喚醒在等待操作資源的線程(隊(duì)列)
  }
  /**
  * 消費(fèi)資源
  */
  public synchronized void destroy() {
  while (!flag) {
  try {
  wait();
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  System.out.println(Thread.currentThread().getName() + "消費(fèi)者****" + number);
  flag = false;
  notifyAll();
  }
  }
登錄后復(fù)制

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

Thread-0生產(chǎn)者------------412
  Thread-2消費(fèi)者****412
  Thread-0生產(chǎn)者------------413
  Thread-3消費(fèi)者****413
  Thread-1生產(chǎn)者------------414
  Thread-2消費(fèi)者****414
  Thread-1生產(chǎn)者------------415
  Thread-2消費(fèi)者****415
  Thread-0生產(chǎn)者------------416
  Thread-3消費(fèi)者****416
  Thread-1生產(chǎn)者------------417
  Thread-3消費(fèi)者****417
  Thread-0生產(chǎn)者------------418
  Thread-2消費(fèi)者****418
  Thread-0生產(chǎn)者------------419
  Thread-3消費(fèi)者****419
  Thread-1生產(chǎn)者------------420
  Thread-2消費(fèi)者****420
登錄后復(fù)制

以上就大功告成了,沒有任何問題

相關(guān)標(biāo)簽:
java速學(xué)教程(入門到精通)
java速學(xué)教程(入門到精通)

java怎么學(xué)習(xí)?java怎么入門?java在哪學(xué)?java怎么學(xué)才快?不用擔(dān)心,這里為大家提供了java速學(xué)教程(入門到精通),有需要的小伙伴保存下載就能學(xué)習(xí)啦!

下載
來源:php中文網(wǎng)
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請聯(lián)系admin@php.cn
最新問題
開源免費(fèi)商場系統(tǒng)廣告
最新下載
更多>
網(wǎng)站特效
網(wǎng)站源碼
網(wǎng)站素材
前端模板
關(guān)于我們 免責(zé)申明 意見反饋 講師合作 廣告合作 最新更新
php中文網(wǎng):公益在線php培訓(xùn),幫助PHP學(xué)習(xí)者快速成長!
關(guān)注服務(wù)號 技術(shù)交流群
PHP中文網(wǎng)訂閱號
每天精選資源文章推送
PHP中文網(wǎng)APP
隨時隨地碎片化學(xué)習(xí)
PHP中文網(wǎng)抖音號
發(fā)現(xiàn)有趣的

Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號