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

来源:互联网 发布:手机qq清空缓存数据 编辑:程序博客网 时间:2024/05/17 08:41

       生产者消费者问题是一个很有名的线程同步问题,以前学操作系统时,没怎么搞懂,直到现在学java学到多线程这一块才搞懂。该问题描述的是两个共享固定大小的缓冲区的线程问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据.
       要解决该问题,就必须让生产者在缓冲区满时休眠(为了简单起见,本例就一个生产者与一个消费者),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。
       下面我用java实现一下:

        本例的生产者是厨师,消费者是服务员
生产者(厨师)只负责生产(做菜),在线程里面用一个循环,使厨师不停的做菜

package producer_and_customer;/** * 生产者:厨师做菜 * @author weixian */public class Product implements Runnable {private Food food;public Product(Food food){this.food=food;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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();
运行结果如下:







1 0
原创粉丝点击