生产者-消费者

1. 问题建模

在餐厅中,厨师是肉的生产者,服务员是肉的消费者。

1.1详细设计

Restaurant类中有未初始化的Meal类和进行工作的WaitPerson对象、Chef对象:前者负责消费Meal,后者负责生产,而且两者需要在构造参数中定义其服务的餐厅。

1.2代码实现
package concurrency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author 杜艮魁
 * @date 2018/1/31
 */


//Meal是Restaurant中未初始化的一个实例,并被其另外两个对象WaitPerson和Chef不断置null和实例化;
class Meal{
    private final int orderNum;

    public Meal(int orderNum) {
        this.orderNum = orderNum;
    }

    @Override
    public String toString() {
        return "Meal "+orderNum;
    }
}

//应当注意WaitPerson是Restaurant中的一个对象,对象创建方式
// WaitPerson waitPerson=new WaitPerson(this) 调用其构造参数如下,以此来使WaitPerson
//作为Restaurant的变量的同时能够操作Restaurant中的变量:即Meal引用状态和唤醒Chef线程
class WaitPerson implements Runnable{
    private Restaurant restaurant;

    public WaitPerson(Restaurant restaurant) {
        this.restaurant = restaurant;
    }

    @Override
    public void run() {
        try{
            while(!Thread.interrupted()){
                synchronized (this){
                    //对条件的判定放在锁里边,防止产生竞态条件
                    while(restaurant.meal==null)//
                        //加锁对象是this-WaitPerson对象:当厨房没有肉时,服务员等待;
                        wait();
                }
                System.out.println("waiter got "+restaurant.meal);

                //Meal不为null时Chef类中用this加锁的代码块被挂起。而以下代码将Meal置为null,因此需要唤醒Chef对象,修改meal引用;
                synchronized (restaurant.chef){
                    //服务员已经拿到肉,此时将肉实例设置为空,并唤醒等待上行锁的线程
                    restaurant.meal=null;
                    restaurant.chef.notifyAll();//fixme notifyAll()相当于this.notifyAll(),唤醒的是等待当前对象监视器的所有线程而非等待Restaurant对象中Chef对象监视器的线程;
                }
            }
        }catch (InterruptedException e){
            System.out.println("waiter interrupted");
        }
    }
}

//含义同WaitPerson
class Chef implements Runnable{
    private int count=0;
    Restaurant restaurant;

    public Chef(Restaurant restaurant) {
        this.restaurant = restaurant;
    }

    @Override
    public void run() {
        try{
            while(!Thread.interrupted()){
                synchronized (this){
                    while(restaurant.meal!=null)
                        wait();
                }
                if(++count==10){
                    System.out.println("out of food,closing");
                    restaurant.exec.shutdownNow();//注意停止的方法仍然是调用Restaurant中的方法
                }
                System.out.println("order up!");//要上菜啦!!
                synchronized (restaurant.waitPerson){
                    restaurant.meal=new Meal(count);
                  //对应tag1处waitPerson发现"Meal"实例不为空时,在synchronized(this-waitPerson)代码块中调用wait——这句代码唤醒wait()的等待
                    restaurant.waitPerson.notifyAll();
                }
                TimeUnit.MILLISECONDS.sleep(100);
            }
        }catch (InterruptedException e){
            System.out.println("chef interrupted");
        }
    }
}

public class Restaurant {
    Meal meal;
    WaitPerson waitPerson=new WaitPerson(this);
    Chef chef=new Chef(this);

    ExecutorService exec= Executors.newCachedThreadPool();

    public Restaurant() {//创建对象时开始执行这两个线程
        exec.execute(chef);
        exec.execute(waitPerson);
    }

    public static void main(String[] args) {
        new Restaurant();
    }
}

posted on 2018-04-21 14:05  coderDu  阅读(108)  评论(0编辑  收藏  举报