包括的な実際の戦闘:「生産者/消費者モデル」
マルチスレッド開発で最も有名なケースは、生産者/消費者モデルです。この操作の主なフローは次のとおりです。
- プロデューサーは情報コンテンツの制作に責任があります
- プロデューサーが完全な情報を完成させるときはいつでも、コンシューマーはそこから情報を取得する必要があります
- 生産者が生産を終了していない場合、消費者は生産が完了するのを待つ必要があります。消費者が情報を消費していない場合、生産者は消費者が情報の消費を完了するのを待ってから生産を続行する必要があります。
生産者と消費者の基本的なプログラムモデル
プロデューサーとコンシューマーは、2つの独立したスレッドのようなオブジェクトとして定義できますが、現在生成されているデータには次の構成を使用できます。
- データ1:タイトル= lyz、コンテンツ=無敵;
- データ2:タイトル= zky、コンテンツ=野菜;
コンシューマーとプロデューサーは2つの独立したスレッドであるため、2つの独立したスレッド間にデータ保存の集中ポイントが必要です。これにより、保存するメッセージクラスを定義できます。基本
モデルプログラムの基本構造
class Producer implements Runnable{
private Message msg;
public Producer(Message msg) {
this.msg = msg;
}
public void run() {
for(int x =0; x<100; x++) {
if(x%2 == 0) {
this.msg.setTitle("lyz");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.msg.setContent("无敌");
} else {
this.msg.setTitle("zky");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.msg.setContent("菜鸡");
}
}
}
}
class Consumers implements Runnable{
private Message msg;
public Consumers(Message msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x=0;x<100;x++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.msg.getTitle() +" - "+ this.msg.getContent() );
}
}
}
class Message {
private String title;
private String content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
public class Consumer {
public static void main(String[] args) {
Message msg = new Message();
new Thread(new Producer(msg)).start(); //启动生产者线程
new Thread(new Consumers(msg)).start(); //启动消费者线程
}
}
コードの実行を通じて、現時点で見つかった2つの主な問題があります。
- データが同期していません。
- 1つを生産し、1つを取り去りますが、繰り返しの生産と繰り返しの除去の問題があることがわかりました。
生産者/消費者同期の問題を解決する
問題を解決したい場合、最初に解決するのはデータ同期処理の問題です。データ同期を解決したい場合、最も簡単な方法は、synchronizedキーワードを使用して同期コードブロックまたは同期方法を定義することです。今回は、同期処理をクラスのメッセージ完了に直接行うことができます。
同期操作を解決します
package per.lyz.thread_study;
class Producer implements Runnable{
private Message msg;
public Producer(Message msg) {
this.msg = msg;
}
public void run() {
for(int x =0; x<100; x++) {
if(x%2 == 0) {
this.msg.set("lyz","无敌");
} else {
this.msg.set("zky","菜鸡");
}
}
}
}
class Consumers implements Runnable{
private Message msg;
public Consumers(Message msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x=0;x<100;x++) {
System.out.println(this.msg.get());
}
}
}
class Message {
private String title;
private String content;
public synchronized void set(String title, String content) {
this.title = title;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content;
}
public synchronized String get() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.title +" - " + this.content;
}
}
public class Consumer {
public static void main(String[] args) {
Message msg = new Message();
new Thread(new Producer(msg)).start(); //启动生产者线程
new Thread(new Consumers(msg)).start(); //启动消费者线程
}
}
同期処理を実行するときは同期オブジェクトが必要であるため、この時点で処理するために同期操作をメッセージクラスに渡すのが最も適切です。現時点では、データは通常一貫していますが、繰り返しの生産があり、繰り返しの問題がまだ存在していることがわかります。
Objectクラスを使用して繰り返しの問題を解決する
消費者生産者問題を解決するための最善の解決策は、待って、目を覚ますメカニズム。待機とウェイクアップのメカニズムに関しては、主にObjectで提供されるメソッドに依存しています。
- 待機メカニズム:
- 死等:public final void wait()throws InterruptedException;
- 待機時間を設定します。publicfinalvoidwait(long timeout)throws InterruptedException;
- 待機時間を設定します。publicfinalvoidwait(long timeout、int nanos)throws InterruptedException;
- ウェイクアップメカニズム:
- 最初の待機中のスレッドをウェイクアップします。publicfinalvoidnotify();
- 待機中のすべてのスレッドをウェイクアップします:public final void notifyAll();(優先度の高いスレッドが最初に実行される場合があります)
現在の問題は、Messageクラスを介して処理する必要があります。
重複する問題を解決する
class Producer implements Runnable{
private Message msg;
public Producer(Message msg) {
this.msg = msg;
}
public void run() {
for(int x =0; x<100; x++) {
if(x%2 == 0) {
this.msg.set("lyz","无敌");
} else {
this.msg.set("zky","菜鸡");
}
}
}
}
class Consumers implements Runnable{
private Message msg;
public Consumers(Message msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x=0;x<100;x++) {
System.out.println(this.msg.get());
}
}
}
class Message {
private String title;
private String content;
private boolean flag; //表示生产或消费形式,=True允许生产,不允许消费,反之相反
public synchronized void set(String title, String content) {
if(!this.flag) {
//无法进行生产,应该等待被消费
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.title = title;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content;
this.flag = false; //已经生产完成
super.notify(); //唤醒可能的等到线程
}
public synchronized String get() {
if(this.flag) {
//还未生产,需要等待
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
return this.title +" - " + this.content;
}finally {
//不管如何都要执行
this.flag = true;
super.notify(); //唤醒可能的等待线程
}
}
}
public class Consumer {
public static void main(String[] args) {
Message msg = new Message();
new Thread(new Producer(msg)).start(); //启动生产者线程
new Thread(new Consumers(msg)).start(); //启动消费者线程
}
}
この形式の処理は、マルチスレッド開発で最も原始的な処理ソリューションです。待機、同期、およびウェイクアップメカニズム全体は、ネイティブコードを介して開発者によって制御されます。