34-Comprehensive combat: "producer-consumer model"

Comprehensive actual combat: "producer-consumer model"

  The most famous case in multithreaded development is the producer-consumer model. The main flow of this operation is as follows:

  1. The producer is responsible for the production of information content
  2. Whenever the producer completes a complete piece of information, the consumer must take the information from it
  3. If the producer has not finished the production, the consumer has to wait for its production to complete. If the consumer has not consumed the information, the producer should wait for the consumer to complete the information consumption before proceeding with the production.

Basic program model of producer and consumer

  The producer and consumer can be defined as two independent thread-like objects, but the following composition can be used for the data currently produced:

  • Data 1: title = lyz, content = invincible;
  • Data 2: title = zky, content = vegetable;

Since the consumer and the producer are two independent threads, there needs to be a data storage concentration point between the two independent threads, so you can define a Message class for storage. Basic structure of
basic model program
r16kef.png

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();		//启动消费者线程
	}
}

Through code execution, there are two main problems found at this time:

  • Data is out of sync;
  • Produce one and take one away, but found that there is a problem of repeated production and repeated removal;

Solve the producer-consumer synchronization problem

  If you want to solve the problem, the first thing to solve is the data synchronization processing problem. If you want to solve the data synchronization, the easiest way is to use the synchronized keyword to define the synchronization code block or synchronization method, so at this time, the synchronization processing can be directly in the Message Completed in the class.
Resolve synchronization operations

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();		//启动消费者线程
	}
}

There must be a synchronization object when performing synchronization processing, so it is most appropriate to hand the synchronization operation to the Message class for processing at this time. At this time, the data is normally consistent, but it is found that there is repetitive production and repetitive problems still exist.

Use Object class to solve repetitive problems

  To solve the consumer producer problem, the best solution is to useWait and wake up mechanism. As for the waiting and wake-up mechanism, it mainly relies on the methods provided in Object:

  • Waiting mechanism:
    • 死等:public final void wait() throws InterruptedException;
    • Set the waiting time: public final void wait(long timeout) throws InterruptedException;
    • Set the waiting time: public final void wait(long timeout, int nanos) throws InterruptedException;
  • Wake-up mechanism:
    • Wake up the first waiting thread: public final void notify();
    • Wake up all waiting threads: public final void notifyAll(); (threads with high priority may be executed first)

The current problem should be handled through the Message class.
Solve duplicate problems

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();		//启动消费者线程
	}
}

This form of processing is the most primitive processing solution in multi-threaded development. The entire wait, synchronization, and wake-up mechanism are controlled by the developer through native code.

Guess you like

Origin blog.csdn.net/MARVEL_3000/article/details/111567465