您的位置:首页 > 其它

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

2016-09-03 23:07 435 查看
生产者消费者问题是一个很有名的线程同步问题,以前学操作系统时,没怎么搞懂,直到现在学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();
运行结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐