线程协作-生产者/消费者问题

2019-04-27  本文已影响0人  Aluha_f289

实例

package demo3;

import java.util.ArrayList;
import java.util.List;

/**
 * 线程与线程协作(通信),生产者/消费者
 * 生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。
 * (关键)该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
 * 要解决该问题:
 *      就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。
 *      同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者,通常采用线程间通信的方法解决该问题。
 *
 * 定义一个盘子类,可以放鸡蛋和取鸡蛋
 *      盘子里只能放一个鸡蛋,A线程专门往盘子里放鸡蛋,如果盘子里有鸡蛋,则一直等到盘子里没鸡蛋,
 *      B线程专门从盘子里取鸡蛋,如果盘子里没鸡蛋,则一直等到盘子里有鸡蛋。
 *
 */
public class Plate {


        /** 装鸡蛋的盘子 */
        List<Object> eggs = new ArrayList<Object>();

    /**
     * 取鸡蛋
     */
    public synchronized Object getEgg() {
        //如果盘子为空、线程进入阻塞
        while (eggs.size() == 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Object egg = eggs.get(0);
        eggs.clear();// 清空盘子
        //盘子不为空(执行线程),唤醒阻塞队列的某线程到就绪队列
        notify();
        System.out.println("拿到鸡蛋");
        return egg;
    }

    /**
     *  放鸡蛋
     */
    public synchronized void putEgg(Object egg) {
        //判断盘子是否为空,放入一个鸡蛋,
        while (eggs.size() > 0) {
            try {
                wait();//盘子非空,执行等待,这个A线程进入阻塞队列(在wait方法说明中,也推荐使用while)
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        eggs.add(egg);// 往盘子里放鸡蛋
        //假设CPU又调度了一个A线程
        notify();// 唤醒阻塞队列的某线程到就绪队列
        System.out.println("放入鸡蛋");
    }

    /**
     * 放鸡蛋线程
     */
    static class AddThread implements Runnable  {
        private Plate plate;
        private Object egg = new Object();
        public AddThread(Plate plate) {
            this.plate = plate;
        }
        public void run() {
            plate.putEgg(egg);
        }

    }

    /**
     * 取鸡蛋线程
     */
    static class GetThread implements Runnable  {
        private Plate plate;
        public GetThread(Plate plate) {
            this.plate = plate;
        }
        public void run() {

            plate.getEgg();

        }

    }

    public static void main(String args[]) {
        Plate plate = new Plate();
        for(int i = 0; i < 10; i++) {
            new Thread(new AddThread(plate)).start();
            new Thread(new GetThread(plate)).start();
        }
    }

}

运行结果

放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋

Process finished with exit code 0

学习于https://blog.csdn.net/ghsau/article/details/7433673

上一篇下一篇

猜你喜欢

热点阅读