Java多线程系列(9)--生产者和消费者

情景描述:请考虑这样一个饭店,它有一个厨师和一个服务员。这个服务员必须等待厨师准备好膳食。当厨师准备好时,他会通知服务员,之后服务员上菜,然后返回继续等待。这是一个任务协作的实例:厨师代表生产者,而服务员代表消费者。两个任务必须在膳食被生产和消费时进行握手,而系统必须以有序的方式关闭。下面给出相应的代码:

饭店:

package ConsumerAndProduct;

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

/**
 * Created by LKL on 2017/2/22.
 */
public class Restaurant {
    Meal meal;
    //线程池
    ExecutorService exec = Executors.newCachedThreadPool();
    WaitPerson waitPerson = new WaitPerson(this);
    Chef chef =new Chef(this);
    public Restaurant(){
        exec.execute(chef);
        exec.execute(waitPerson);
    }
    public static void main(String[] args){
        new Restaurant();
    }
}

厨师(生产者):

package ConsumerAndProduct;

import java.util.concurrent.TimeUnit;


/**
 * Created by LKL on 2017/2/22.
 * 厨师,生产者
 */
public class Chef implements Runnable {
    private Restaurant restaurant;
    private int count = 0;

    public Chef(Restaurant r) {
        restaurant = r;
    }

    public void run() {
        try {
            while (!Thread.interrupted()) {
                synchronized (this) {
                    while (restaurant.meal != null) {
                        wait();
                    }
                }
                if (++count == 10) {
                    System.out.print("Out of food.closing");
                    restaurant.exec.shutdownNow();
                }
                System.out.println("Order up!");
                synchronized (restaurant.waitPerson) {
                    restaurant.meal = new Meal(count);
                    restaurant.waitPerson.notifyAll();
                }

                   TimeUnit.MILLISECONDS.sleep(100);
                  }
                } catch (InterruptedException e) {
                   System.out.println("Chef interrupted");
                }
    }
}

服务员(消费者):

package ConsumerAndProduct;

/**
 * Created by LKL on 2017/2/22.
 * 服务员,消费者
 */
public class WaitPerson implements Runnable{
    private Restaurant restaurant;

    public WaitPerson(Restaurant r) {
        restaurant = r;
    }
    public void run(){
        try {
         while(!Thread.interrupted()){

                synchronized (this) {
                    while (restaurant.meal == null){
                        wait();
                    }
                }
                System.out.println("WaitPerson got" + restaurant.meal);
                synchronized (restaurant.chef){
                    restaurant.meal=null;
                    //可以用于具体唤醒哪一个线程,使用notify()
                    restaurant.chef.notifyAll();
                }
            }
        }catch (InterruptedException e) {
            System.out.println("WaitPerson interrupted");
            }
    }
}

食物:

package ConsumerAndProduct;

/**
 * Created by LKL on 2017/2/22.
 */
public class Meal {
    private final int orderNum;

    public Meal(int orderNum) {
        this.orderNum = orderNum;
    }
    @Override
    public String toString() {
        return "Meal" +
                + orderNum ;
    }
}

运行上述代码结果如下:

Order up!
WaitPerson gotMeal1
Order up!
WaitPerson gotMeal2
Order up!
WaitPerson gotMeal3
Order up!
WaitPerson gotMeal4
Order up!
WaitPerson gotMeal5
Order up!
WaitPerson gotMeal6
Order up!
WaitPerson gotMeal7
Order up!
WaitPerson gotMeal8
Order up!
WaitPerson gotMeal9
Out of food.closingOrder up!
WaitPerson interrupted
Chef interrupted

补充:

wait():让当前线程进入等待状态,并释放当前锁持有的锁;

notifyAll():唤醒在此对象监视器上的所有线程。

结果分析:
  首先得明白Restaurant是WaitPerson和Chef的交接点。在run()中,WaitPerson(服务生)进入wait()模式,停止其当前线程的任务,直至被Chef(厨师)的notifyAll()唤醒。这是一个单生产者和单消费者的情景,相对简单,只有一个任务将在WaitPerson的锁上等待,即WaitPerson任务本身。
一旦Chef送上Meal并通知WaitPerson,这个Chef将被等待,直至WaitPerson收集到订单并通知Chef,之后Chef就可以烧下一份Meal了。
提高(后续改进):
  使用wait()和notifyAll()解决了单个生产者和消费者问题,生产者不能溢出接受者的缓冲区,而这生产者比消费者速度快时完全有可能发生。如果消费者比生产者速度快,那么消费者不能读取多次相同数据。

文章只是作为自己的学习笔记,借鉴了网上的许多案例,如果觉得阔以的话,希望多交流,在此谢过…

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值