Java多线程:生产者-消费者模型

生产者生产,消费者消费,理想的情况下是生产者每生产一个产品,消费者就消费一个产品,生产者还没有生产的时候消费者等待,消费者还没有消费完产品的时候生产者等待。

class Producer implements Runnable{    // 生产者
	private Message msg;
	
	public Producer(Message msg) {
		this.msg = msg;
	}
	
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if(i % 2 == 0) {
				this.msg.setTitle("产品-1");
				this.msg.setContent("oppo手机");
			}
			else {
				this.msg.setTitle("产品-2");
				this.msg.setContent("vivo手机");
			}
		}
	}
}

class Consumer implements Runnable{    // 消费者
	private Message msg;
	
	public Consumer(Message msg) {
		this.msg = msg;
	}
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("消费则消费:" + this.msg.getTitle() + " -  " + this.msg.getContent());;
		}
	}
	
}

class Message{    // 生产者和消费者通过Message建立联系
	private String title;
	private String content;
	
	public void setContent(String content) {
		this.content = content;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	

	public String getTitle() {
		return title;
	}
	public String getContent() {
		return content;
	}
	
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		
		Message msg = new Message();
		new Thread(new Producer(msg)).start();	// 启动生产者线程
		new Thread(new Consumer(msg)).start();	// 启动消费者线程
	}
}

运行结果显示出现了数据不同步的问题,那么接下来就解决数据不同步的问题

修改代码:

class Message{
	private String title;
	private String content;
	
	// 进行同步处理
	public synchronized void set(String title, String content) {
		this.title = title;
		this.content = content;
	}
	
	public synchronized String get() {
		return this.title + " -  " + this.content;
	
	}
}

把同步处理放到Message类后可以解决数据不同步问题,但是不能解决数据重复问题。

如果想要解决生产者与消费者的问题,最好的解决方案是使用等待与唤醒机制。

对于等待和唤醒的操作机制主要依靠的是Object类提供的方法处理的:

  • 等待:2,3可以设置等待时间
  1. public final void wait​() throws InterruptedException

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

  1. public final void wait​(long timeout) throws InterruptedException

Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed. The current thread must own this object's monitor.

  1. public final void wait​(long timeout, int nanos) throws InterruptedException

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.

  • 唤醒:
  1. 唤醒第一个等待线程:public final void notify​()
  2. 唤醒所有等待线程:public final void notifyAll​()

notify()唤醒第一个等待的线程,notifyAll()唤醒所有等待的线程,这样优先级高的有可能会先执行

再次修改Message类:

class Message{
	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;
		this.content = content;
		this.flag = false;	// 已经生产过了
		super.notify();		// 通知正在等待的消费者可以消费了
	}
	
	public synchronized String get() {
		if(this.flag == true) {		// 如果不能消费则应该等待
			try {
				super.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		try {	// 先算出return后的表达式的值,然后执行finally,最后return
			return this.title + " -  " + this.content;
		}finally {
			flag = true;	// 消费过了
			super.notify();	// 通知正在等待的生产者可以生产了
		}
		
	}
}

运行结果:

完整代码:

class Producer implements Runnable{
	private Message msg;
	
	public Producer(Message msg) {
		this.msg = msg;
	}
	
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if(i % 2 == 0) {
				System.out.println("生产产品1");
				this.msg.set("产品-1", "oppo手机");
			}
			else {
				System.out.println("生产产品2");
				this.msg.set("产品-2", "vivo手机");
			}
		}
	}
}

class Consumer implements Runnable{
	private Message msg;
	
	public Consumer(Message msg) {
		this.msg = msg;
	}
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("消费则消费:" + this.msg.get());
		}
	}
	
}

class Message{
	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;
		this.content = content;
		this.flag = false;	// 已经生产过了
		super.notify();		// 通知正在等待的消费者可以消费了
	}
	
	public synchronized String get() {
		if(this.flag == true) {		// 如果不能消费则应该等待
			try {
				super.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		try {	// 先算出return后的表达式的值,然后执行finally,最后return
			return this.title + " -  " + this.content;
		}finally {
			flag = true;	// 消费过了
			super.notify();	// 通知正在等待的生产者可以生产了
		}
		
	}
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		
		Message msg = new Message();
		new Thread(new Producer(msg)).start();	// 启动生产者线程
		new Thread(new Consumer(msg)).start();	// 启动消费者线程
	}
}
发布了238 篇原创文章 · 获赞 104 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/hpu2022/article/details/103344143