スレッドプロデューサーとコンシューマーケースの間の古典的な操作ケース
基本的なプログラムモデル:
package Project.Study.Multithreading;
class Message{
private String title; //保存信息的标题
private String content; //保存信息的内容
public void setTitle(String title) {
this.title = title;
}
public void setContent(String content) {
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
}
class Producer implements Runnable{ //定义生产者
private Message msg=null;
public Producer(Message msg){
this.msg=msg;
}
@Override
public void run(){
for (int x=0;x<50;x++){ //生产50次数据
if(x%2==0){
this.msg.setTitle("小关"); //定义title属性
try {
Thread.sleep(100); //延迟操作
}catch (InterruptedException e){
e.printStackTrace();
}
this.msg.setContent("学习Java");//设置content属性
}else{
this.msg.setTitle("小梁"); //设置title属性
try {
Thread.sleep(100); //延迟操作
}catch (InterruptedException e){
e.printStackTrace();
}
this.msg.setContent("学习python");//设置content属性
}
}
}
}
class Consumer implements Runnable{
private Message msg;
public Consumer(Message msg){
this.msg=msg;
}
@Override
public void run(){
for(int x=0;x<50;x++){
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(this.msg.getTitle()+"-->"+this.msg.getContent());
}
}
}
public class Test10 {
public static void main(String []args){
Message msg=new Message();
new Thread(new Producer(msg)).start();
new Thread(new Consumer(msg)).start();
}
}
//结果:
//小梁-->学习Java
//小关-->学习python
//小梁-->学习Java
//小关-->学习python
//小梁-->学习Java
//小关-->学习python
//小梁-->学习Java
//小关-->学习python
//小梁-->学习Java
//(...)
もともとプログラムの予想される出力は、Xiaoguan-> Learning Java、Xiaoliang-> Learning pythonです
が、明らかに問題があり、設定されたデータがずれており、データが繰り返し取り出され、繰り返し設定されています。
データの乱れの問題を解決する
データの不整合は完全に非同期操作によるものであるため、同期処理を使用する必要があります。
例:データの乱れの問題を解決するために同期に参加する
package Project.Study.Multithreading;
class Message2{
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 void get(){
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(this.title+"-->"+this.content);
}
}
class Producer2 implements Runnable{
private Message2 meg=null;
public Producer2(Message2 msg){
this.meg=msg;
}
@Override
public void run(){
for(int x=0;x<20;x++){
if(x%2==0){
this.meg.set("小关","学习Java");
}else{
this.meg.set("小梁","学习Python");
}
}
}
}
class Consumer2 implements Runnable{
private Message2 msg=null;
public Consumer2(Message2 msg){
this.msg=msg;
}
@Override
public void run(){
for (int x=0;x<20;x++){
this.msg.get();
}
}
}
public class Test11 {
public static void main(String []args)throws Exception{
Message2 msg=new Message2();
new Thread(new Producer2(msg)).start();
new Thread(new Consumer2(msg)).start();
}
}
//结果:
//小梁-->学习Python
//小梁-->学习Python
//小梁-->学习Python
//小梁-->学习Python
//(...)
上記の手順により、データの不整合の問題は解決されますが、削除と設定の繰り返しの問題は依然として残っています。
データの重複を解決する
マルチスレッドのオブジェクトクラスのサポート
番号。 | 方法 | タイプ | 説明文 |
---|---|---|---|
1 | public final void wait()は、InterruptedExceptionをスローします | 普通の | スレッド待機中 |
2 | public final void notify() | 普通の | 最初の待機中のスレッドを起こす |
3 | public final void notifyAll() | 普通の | 待機中のすべてのスレッドを起こす |
一般に、待機中のスレッドはすべて順番に配置されます。
notify()メソッドを使用すると、最初の待機中のスレッドが起こされ
、notifyAll()メソッドを使用すると、すべての待機中のスレッドが起こされます。最も優先順位の高いスレッドが最初に実行されます。
例:
package Project.Study.Multithreading;
class Message3{
private String title;
private String content;
private boolean flag=true;
//flag==true:表示可以生产,但是不能拿走
//flag==false:表示可以取走,但是不能生产
public synchronized void set(String title,String content){
if(this.flag==false){
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 void get(){
if (this.flag==true){ //未生产,不能取走
try {
super.wait(); //等待
}catch (InterruptedException e){
e.printStackTrace();
}
}
try {
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(this.title+"-->"+this.content);
this.flag=true; //已经取走了,可以继续生产
super.notify(); //唤醒等待线程
}
}
class Producer3 implements Runnable{
private Message3 meg;
public Producer3(Message3 msg){
this.meg=msg;
}
@Override
public void run(){
for(int x=0;x<10;x++){
if(x%2==0){
this.meg.set("小关","学习Java");
}else{
this.meg.set("小梁","学习Python");
}
}
}
}
class Consumer3 implements Runnable{
private Message3 msg;
public Consumer3(Message3 msg){
this.msg=msg;
}
@Override
public void run(){
for (int x=0;x<10;x++){
this.msg.get();
}
}
}
public class Test12 {
public static void main(String []args){
Message3 msg=new Message3();
new Thread(new Producer3(msg)).start();
new Thread(new Consumer3(msg)).start();
}
}
//结果:
//小关-->学习Java
//小梁-->学习Python
//小关-->学习Java
//小梁-->学习Python
//小关-->学习Java
//小梁-->学习Python
//小关-->学习Java
//小梁-->学习Python
//小关-->学习Java
//小梁-->学习Python
上記の手順は、データの不整合、繰り返しのデータ削除、繰り返しの設定の問題を解決します。
ヒント:
sleep()とwait()の違い:
1.sleep()はThreadクラスによって定義された静的メソッドです。つまり、スレッドはスリープし、他のスレッドに実行機会を与えますが、監視状態は維持され、自動的に再開されます
。2.wait( )Objectクラスによって定義されたメソッドです。つまり、スレッドは、notify()またはnotifyAll()が実行されるまで待機します。