天天看点

多线程解决生产者与消费者问题

       生产者消费者问题是一个很有名的线程同步问题,以前学操作系统时,没怎么搞懂,直到现在学java学到多线程这一块才搞懂。该问题描述的是两个共享固定大小的缓冲区的线程问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据.

       要解决该问题,就必须让生产者在缓冲区满时休眠(为了简单起见,本例就一个生产者与一个消费者),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。

       下面我用java实现一下:

        本例的生产者是厨师,消费者是服务员

生产者(厨师)只负责生产(做菜),在线程里面用一个循环,使厨师不停的做菜

package producer_and_customer;
/**
 * 生产者:厨师做菜
 * @author weixian
 */
public class Product implements Runnable {
	private Food food;
	
	public Product(Food food){
		this.food=food;
	}
	@Override
	public void run() {
		for(int i=0;i<50;i++){
			if(i%2==0){
				food.setFood("辣椒炒肉","很辣很好吃!");
			}else{
				food.setFood("鸡蛋干炒肉","有点臭,不好吃!");
			}
		}
	}
}
           

这里我使用一个循环使厨师不停的生产两道菜,由于启用的是线程,没有设置优先级,所有菜名和菜的描述在输出时可能会不对应,所有这里我使用同步方法实现,代码在后面贴出。

消费者(服务员)只负责消费(上菜),在线程里面也用一个循环,使服务员不停的做菜

package producer_and_customer;
/**
 * 消费者:服务员上菜
 * @author weixian
 */
public class Customer implements Runnable{
	private Food food;
	
	public Customer(Food food){
		this.food=food;
	}
	@Override
	public void run() {
		for(int j=0;j<50;j++){
			food.getFood();
		}
	}
}
           

这里同生产者厨师一样,输出也有可能不对应,所以也必须使用同步方法,同步方法写在Food类中

package producer_and_customer;
public class Food {
	private String name;
	private String des;
	private boolean flag = true; //true 代表可以生产  false代表可以消费

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public synchronized void setFood(String name,String des){
		if(!flag){
			try {
				this.wait();  //进入等待状态,不能生产
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.setName(name);
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.setDes(des);
		flag = false;  //表示可以消费了
		this.notify(); //唤醒当前线程
	}
	
	public String getDes() {
		return des;
	}
	
	public synchronized void getFood(){
		if(flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(this.getName()+":"+this.getDes());
		flag = true; //表示可以生产了
		this.notify(); //唤醒当前线程
	}
	
	public void setDes(String des) {
		this.des = des;
	}
	@Override
	public String toString() {
		return "Food [name=" + name + ", des=" + des + "]";
	}
	public Food(String name, String des) {
		super();
		this.name = name;
		this.des = des;
	}
	public Food() {
		super();
	}
}
           

在Food类中不仅有两个同步方法分别对应生产者与消费者,在其中还定义了一个变量flag,通过这个flag来控制生产者的生产与消费者的消费。因为这两个操作不能同时进行,所以在生产者(厨师)在生产(做菜)的时候,消费者(服务员)不能消费(上菜)。服务员应该等待厨师把才做好,才能上菜。此时服务员等待,等到厨师做好后唤醒服务员上菜,反之亦然。道理就只有一个,两个操作不能同时进行。

这个问题的核心就是要解决两个问题:

1、菜名与菜的描述一定要对应。所以要使用同步

2、厨师与服务员的操作不能同时进行。所以要用flag控制线程的等待与唤醒

通过在主类中启动线程运行

Food food = new Food();
Product product = new Product( food );
Customer customer = new Customer(food);
new Thread(product).start();
new Thread(customer).start();
           

运行结果如下:

多线程解决生产者与消费者问题

继续阅读