生产者与消费者模型(唤醒机制实现线程之间的通讯)

生产者与消费者模型(唤醒机制实现线程之间的通讯)


前言

项目场景:生产者,消费者两种对象。只有生产者的生产商品和消费者消费的商品达到平衡,才不会出现供大于求或供不应求的场景。
解决方法:采用同步的方法,使得多个线程之间达到平衡,或者说是线程之间能够通信。
举个例子:一个厨师如果不跟顾客沟通,一个劲的做饭,那是不是造成了浪费。 一个顾客也是,如果不跟初始沟通,自己要吃啥,吃多少,那岂不是自己的胃就任人摆布啦。也不至于你人在家里,厨师在饭店,你想吃他在做但是就是吃不到。于是这里就需要一个通信机制来解决这些问题啦。


一、同步是什么(搜集了各种解释)?

同步(协同步调):多个线程开始运行时,受到操作系统,硬件等等一系列的因素的制约,运行时顺序是不可控的!!!通过程序控制多线程的运行顺序或者步骤,就是同步!
同步:同步是指一个进程在执行某个请求的时候,如果该请求需要一段时间才能返回信息,那么这个进程会一直等待下去,直到收到返回信息才继续执行下去。就是必须一件一件事做,等前一件做完了才能做下一件事
同步:当程序1调用程序2时,程序1停下不动,直到程序2完成回到程序1来,程序1才继续执行下去。
同步:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。

二、如何实现同步

1.加锁

加锁是一种实现同步的手段,但是效率不高。

2.唤醒机制

2.1:一般是用在两个线程之间,运行时顺序是不可而控的!!!
使用唤醒机制实现同不可控。
2.2:使用共有的对象作为唤醒的对象存在(盘子)
2.3:必须要加同步锁(synchronized)
2.4:同步锁的钥匙必须是共有对象
wait() 让线程进入等待状态
notify() 唤醒线程
notifyALL() 唤醒所有线程

3.守护线程(补充知识点)

他所依赖的线程结束,他就结束。
让顾客依赖于厨师。
解决了顾客线程陷入死循环关不掉的问题。

thread(依赖线程的名称).setDaemon(true);

三.代码实现

1.盘子(作为中间介质,共有对象,来连接多个线程之间的通信)

public class Disk {
	//盘子上面的食物
   private  String foodname;
   //判断盘子是否为空
   private  boolean full;

public String getFoodname() {
	return foodname;
}

public void setFoodname(String foodname) {
	this.foodname = foodname;
}

public boolean isFull() {
	return full;
}

public void setFull(boolean full) {
	this.full = full;
}

public Disk() {
	super();
}

public Disk(String foodname, boolean full) {
	super();
	this.foodname = foodname;
	this.full = full;
}
   

}

2.顾客

public class Customer implements Runnable{
	private Disk disk;

	public Disk getDisk() {
		return disk;
	}

	public void setDisk(Disk disk) {
		this.disk = disk;
	}

	
//构造函数
	public Customer(Disk disk) {
		super();
		this.disk = disk;
	}

	public Customer() {
		super();
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		eat();
	}

	private void eat() {
		// TODO Auto-generated method stub
		while(true) 
			//死循環,一直用於判斷盤子内是否有實物。
		{
			//
			//2.3必须加同步锁,且2.4同步锁的钥匙必须是共有对象
			synchronized (this.disk) {
				if(this.disk.isFull()) 
				{
					//只要盤子裏面有東西,就一直吃東西。
					System.out.println(Thread.currentThread().getName()+"吃了"+this.disk.getFoodname());
				//吃完后盤子為空
				this.disk.setFull(false);
				
				
				
				//唤醒机制的使用
				this.disk.notify();
				try {
					this.disk.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				}
				else {
					try {
						this.disk.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			
		}
		
	}
	

}

3.厨师

import java.util.Random;

public class Producter  implements Runnable{
	private String[] foods;
	private Disk disk;
	private Random random;
	public String[] getFoods() {
		return foods;
	}

	public void setFoods(String[] foods) {
		this.foods = foods;
	}
	public Random getRandom() {
		return random;
	}

	public void setRandom(Random random) {
		this.random = random;
	}
	
	
	public Producter(Disk disk) {
		super();
		this.foods = new String[]{"牛肉面","热干面","米线","拉面"};
		this.disk =disk;
		this.random=new Random();
	}
	
	public Producter() {
		super();
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		cookie();
	}

	private void cookie() 
	{
		// TODO Auto-generated method stub
		for(int i=0;i<10;i++)
		{
			synchronized (this.disk) {
				//做饭也是有条件的,只有盘子是空的时候。才做饭
				if(!this.disk.isFull())
			{
				//随机做一种食物
				int index=this.random.nextInt(this.foods.length);
				String food=this.foods[index];
				System.out.println(Thread.currentThread().getName()+"制作了一种食物"+food);
				this.disk.setFoodname(food);
				this.disk.setFull(true);
				this.disk.notify();
				try {
					this.disk.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
		    }
				else {
					try {
						this.disk.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
			}
			}
			
		}
			
	}
}

测试类

public class test {
	public static void main(String[] args) {
		Disk disk=new Disk();
		//保證顧客和厨師使用的是同一個盤子
		Producter producter =new Producter(disk);
     	Customer customer=new Customer(disk);
		
		Thread thread1= new Thread(producter);
		Thread thread2=new Thread(customer);
	//将顾客做成守护线程,让他依赖厨师。解决了顾客线程陷入死循环关不掉的问题
		thread2.setDaemon(true);
		thread1.start();
		thread2.start();
	}

}

总结

通过对生产者与消费者模型的不断完善,从刚开始解决线程关不掉,采用守护线程巧妙化解。然后又出现了线程不同步问题,采用唤醒机制。必须要有一个共同的对象来唤醒他们。顺利解决了牛头不对马嘴的问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值