Java マルチスレッドの同時協調的なプロデューサー/コンシューマー設計パターン
2 つのスレッド、1 つのプロデューサーと 1 つのコンシューマー
需要シナリオ
2 つのスレッド、1 つは生産を担当し、1 つは消費を担当し、1 つのプロデューサーが 1 つを生成し、コンシューマーが 1 つを消費します
関連する問題
同期の問題:リソースが複数のスレッドによって同時にアクセスされる場合でも、同じ整合性が維持されます。一般的に使用される同期方法は、マーキング メカニズムまたはロック メカニズムを使用することです。wait() / nofity() メソッドは、基本クラス Object の 2 つのメソッドです。つまり、すべての Java クラスがこれら 2 つのメソッドを持つことになります。同期メカニズムを実装します。
Wait() メソッド: バッファーがいっぱいまたは空の場合、プロデューサー/コンシューマー スレッドは自身の実行を停止し、ロックを放棄し、他のスレッドが実行できるように待機状態になります。
Notify() メソッド: プロデューサ/コンシューマがバッファにプロダクトを入れたり、バッファからプロダクトを取り出したりするとき、実行可能な通知を待機中の他のスレッドに送信し、同時にロックを放棄して自身を待機状態にします。
コード実装(合計3つのクラスと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
/**
* 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();
}
}
}
りー
印刷結果 /**
* 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();//消费者线程
}
}
複数のスレッド、複数のプロデューサ、複数のコンシューマに問題があります
需要シナリオ
4 つのスレッド、そのうち 2 つは生産を担当します、 2 つは消費を担当し、プロデューサーは 1 つを生産し、コンシューマーは 1 つを消費します
関連する問題
NotifyAll() メソッド: プロデューサー/コンシューマーがバッファーに製品を入れる/取り出すと、待機している他のすべてのユーザーにメッセージを発行しますスレッド 実行可能通知もロックを放棄し、待機状態になります。
コードを再度テストします
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();//消费者线程
}
}
101 は 1 回生成され、2 回消費されました
105 は生成されましたが、消費されませんでした
原因分析
2 つのスレッドがプロデューサーの生産またはコンシューマーの消費を同時に操作する場合、プロデューサーまたは両方のスレッドが存在する場合は、wait() を再度 Notify() します。これは、一方のスレッドがマークを変更し、もう一方のスレッドが再度マークを変更したためです。これは直接実行した場合に判定マークがないことが原因です。
判定マークを一度だけ付けると、実行すべきでないスレッドが実行されてしまいます。データエラーが発生しました。
解決策
while判定マークは、スレッドが実行権を獲得した後に実行したいかどうかの問題を解決します! つまり、wait()の後にnotify()が続くたびに、マークを再度判定する必要があります
コードの改善(if-> in Resource ;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などの特定の値に出力すると、プログラムがロックされているかのようにスタックして実行されます。
原因分析
通知: このパーティがこのパーティを起動するのは 1 つのスレッドだけです。また、while判定マーク+通知は「デッドロック」を引き起こします。
解決策
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();
}
}

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











フロントエンドのサーマルペーパーチケット印刷のためのよくある質問とソリューションフロントエンド開発におけるチケット印刷は、一般的な要件です。しかし、多くの開発者が実装しています...

スキルや業界のニーズに応じて、PythonおよびJavaScript開発者には絶対的な給与はありません。 1. Pythonは、データサイエンスと機械学習でさらに支払われる場合があります。 2。JavaScriptは、フロントエンドとフルスタックの開発に大きな需要があり、その給与もかなりです。 3。影響要因には、経験、地理的位置、会社の規模、特定のスキルが含まれます。

JavaScriptは現代のWeb開発の基礎であり、その主な機能には、イベント駆動型のプログラミング、動的コンテンツ生成、非同期プログラミングが含まれます。 1)イベント駆動型プログラミングにより、Webページはユーザー操作に応じて動的に変更できます。 2)動的コンテンツ生成により、条件に応じてページコンテンツを調整できます。 3)非同期プログラミングにより、ユーザーインターフェイスがブロックされないようにします。 JavaScriptは、Webインタラクション、シングルページアプリケーション、サーバー側の開発で広く使用されており、ユーザーエクスペリエンスとクロスプラットフォーム開発の柔軟性を大幅に改善しています。

同じIDを持つ配列要素をJavaScriptの1つのオブジェクトにマージする方法は?データを処理するとき、私たちはしばしば同じIDを持つ必要性に遭遇します...

この記事の視差スクロールと要素のアニメーション効果の実現に関する議論では、Shiseidoの公式ウェブサイト(https://www.shisido.co.co.jp/sb/wonderland/)と同様の達成方法について説明します。

JavaScriptを学ぶことは難しくありませんが、挑戦的です。 1)変数、データ型、関数などの基本概念を理解します。2)非同期プログラミングをマスターし、イベントループを通じて実装します。 3)DOM操作を使用し、非同期リクエストを処理することを約束します。 4)一般的な間違いを避け、デバッグテクニックを使用します。 5)パフォーマンスを最適化し、ベストプラクティスに従ってください。

フロントエンドのVSCodeと同様に、パネルドラッグアンドドロップ調整機能の実装を調べます。フロントエンド開発では、VSCODEと同様のVSCODEを実装する方法...

Console.log出力の違いの根本原因に関する詳細な議論。この記事では、Console.log関数の出力結果の違いをコードの一部で分析し、その背後にある理由を説明します。 �...
