兩個線程一個生產者個一個消費者
需求情景
兩個線程,一個負責生產,一個負責消費,生產者生產一個,消費者消費一個
『 資源被多個執行緒並發存取時的完整性。常用的同步方法是採用標記或加鎖機制
wait() / nofity() 方法是基類Object的兩個方法,也就意味著所有Java類別都會擁有這兩個方法,這樣,我們就可以為任何物件實作同步機制。
wait()方法:當緩衝區已滿/空時,生產者/消費者執行緒停止自己的執行,放棄鎖,使自己處於等等狀態,讓其他執行緒執行。
notify()方法:當生產者/消費者向緩衝區放入/取出一個產品時,向其他等待的執行緒發出可執行的通知,同時放棄鎖,使自己處於等待狀態。
程式碼實作(共三個類別和一個main方法的測試類別)
Resource.java /** * Created by yuandl on 2016-10-11./** * 资源 */ public class Resource { /*资源序号*/ private int number = 0; /*资源标记*/ private boolean flag = false; /** * 生产资源 */ public synchronized void create() { if (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费; try { wait();//让生产线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } number++;//生产一个 System.out.println(Thread.currentThread().getName() + "生产者------------" + number); flag = true;//将资源标记为已经生产 notify();//唤醒在等待操作资源的线程(队列) } /** * 消费资源 */ public synchronized void destroy() { if (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "消费者****" + number); flag = false; notify(); } }
Producer.java
ProducerConsumerTest.java /**
* Created by yuandl on 2016-10-11.
*
/**
* 生产者
*/
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();
}
}
}
/**
* 消费者
*/
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();
}
}
}
多個線程,多個生產者和多個消費者的問題
多個需求
『兩個個負責消費,生產者生產一個,消費者消費一個涉及問題
notifyAll()方法:當生產者/消費者向緩衝區放入/取出一個產品時,向其他等待的所有線程發出可執行的通知,同時放棄鎖,使自己處於等待狀態。
再次測試代碼
/** * 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();//生产者线程 new Thread(new Consumer(resource)).start();//消费者线程 } }
運行結果
Thread-0生产者------------1 Thread-1消费者****1 Thread-0生产者------------2 Thread-1消费者****2 Thread-0生产者------------3 Thread-1消费者****3 Thread-0生产者------------4 Thread-1消费者****4 Thread-0生产者------------5 Thread-1消费者****5 Thread-0生产者------------6 Thread-1消费者****6 Thread-0生产者------------7 Thread-1消费者****7 Thread-0生产者------------8 Thread-1消费者****8 Thread-0生产者------------9 Thread-1消费者****9 Thread-0生产者------------10 Thread-1消费者****10
透過以上列印結果發現問題
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();//生产者线程 new Thread(new Consumer(resource)).start();//生产者线程 new Thread(new Producer(resource)).start();//消费者线程 new Thread(new Producer(resource)).start();//消费者线程 } }
透過以上列印結果發現問題🜀 05生產了,沒有消費
原因分析
當兩個線程同時操作生產者生產或者消費者消費時,如果有生產者或者的兩個線程都wait()時,再次notify(),由於其中一個線程已經改變了標記而另外一個線程再次往下直接執行的時候沒有判斷標記而導致的。if判斷標記,只有一次,會導致不該運行的執行緒運行了。出現了數據錯誤的情況。
解決方案
while判斷標記,解決了線程獲取執行權後,是否要運行!也就是每次wait()後再notify()時先再次判斷標記
while)
Resource.java
Thread-0生产者------------100 Thread-3消费者****100 Thread-0生产者------------101 Thread-3消费者****101 Thread-2消费者****101 Thread-1生产者------------102 Thread-3消费者****102 Thread-0生产者------------103 Thread-2消费者****103 Thread-1生产者------------104 Thread-3消费者****104 Thread-1生产者------------105 Thread-0生产者------------106 Thread-2消费者****106 Thread-1生产者------------107 Thread-3消费者****107 Thread-0生产者------------108 Thread-2消费者****108 Thread-0生产者------------109 Thread-2消费者****109 Thread-1生产者------------110 Thread-3消费者****110
再次發現問題
印到某個值例如生產完74,程式運作卡死了,好像鎖死了一樣。
原因分析
notify:只能喚醒一個線程,如果本方喚醒了本方,沒有意義。而且while判斷標記+notify會導致」死鎖」。
解決方案
notifyAll解決了本方執行緒一定會喚醒對方執行緒的問題。
最後程式碼改進(Resource中的notify()->notifyAll())
Resource.java
/** * Created by yuandl on 2016-10-11./** * 资源 */ public class Resource { /*资源序号*/ private int number = 0; /*资源标记*/ private boolean flag = false; /** * 生产资源 */ public synchronized void create() { while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费; try { wait();//让生产线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } number++;//生产一个 System.out.println(Thread.currentThread().getName() + "生产者------------" + number); flag = true;//将资源标记为已经生产 notify();//唤醒在等待操作资源的线程(队列) } /** * 消费资源 */ public synchronized void destroy() { while (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "消费者****" + number); flag = false; notify(); } }
告
/** * Created by yuandl on 2016-10-11./** * 资源 */ public class Resource { /*资源序号*/ private int number = 0; /*资源标记*/ private boolean flag = false; /** * 生产资源 */ public synchronized void create() { while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费; try { wait();//让生产线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } number++;//生产一个 System.out.println(Thread.currentThread().getName() + "生产者------------" + number); flag = true;//将资源标记为已经生产 notifyAll();//唤醒在等待操作资源的线程(队列) } /** * 消费资源 */ public synchronized void destroy() { while (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "消费者****" + number); flag = false; notifyAll(); } }
告
〜告

JavaScript字符串替換方法詳解及常見問題解答 本文將探討兩種在JavaScript中替換字符串字符的方法:在JavaScript代碼內部替換和在網頁HTML內部替換。 在JavaScript代碼內部替換字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 該方法僅替換第一個匹配項。要替換所有匹配項,需使用正則表達式並添加全局標誌g: str = str.replace(/fi

因此,在這裡,您準備好了解所有稱為Ajax的東西。但是,到底是什麼? AJAX一詞是指用於創建動態,交互式Web內容的一系列寬鬆的技術。 Ajax一詞,最初由Jesse J創造

本文討論了在瀏覽器中優化JavaScript性能的策略,重點是減少執行時間並最大程度地減少對頁面負載速度的影響。

本文討論了使用瀏覽器開發人員工具的有效JavaScript調試,專注於設置斷點,使用控制台和分析性能。

將矩陣電影特效帶入你的網頁!這是一個基於著名電影《黑客帝國》的酷炫jQuery插件。該插件模擬了電影中經典的綠色字符特效,只需選擇一張圖片,插件就會將其轉換為充滿數字字符的矩陣風格畫面。快來試試吧,非常有趣! 工作原理 插件將圖片加載到畫布上,讀取像素和顏色值: data = ctx.getImageData(x, y, settings.grainSize, settings.grainSize).data 插件巧妙地讀取圖片的矩形區域,並利用jQuery計算每個區域的平均顏色。然後,使用

本文將引導您使用jQuery庫創建一個簡單的圖片輪播。我們將使用bxSlider庫,它基於jQuery構建,並提供許多配置選項來設置輪播。 如今,圖片輪播已成為網站必備功能——一圖胜千言! 決定使用圖片輪播後,下一個問題是如何創建它。首先,您需要收集高質量、高分辨率的圖片。 接下來,您需要使用HTML和一些JavaScript代碼來創建圖片輪播。網絡上有很多庫可以幫助您以不同的方式創建輪播。我們將使用開源的bxSlider庫。 bxSlider庫支持響應式設計,因此使用此庫構建的輪播可以適應任何

數據集對於構建API模型和各種業務流程至關重要。這就是為什麼導入和導出CSV是經常需要的功能。在本教程中,您將學習如何在Angular中下載和導入CSV文件


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3漢化版
中文版,非常好用

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

禪工作室 13.0.1
強大的PHP整合開發環境

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

WebStorm Mac版
好用的JavaScript開發工具