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

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值