生产者、消费者模型——线程间的通信方式

生产者消费者模型——线程间的通信方式
我们俩要进行通信,我把数据传给你,但是我们俩之间传数据不是直接传(调用你,给你传数据),而是咱们俩之间有数据容器,我把数据放容器里,你从容器里取数据。
生产者线程:产生数据,并添加到一个集合(数据容器)
消费者线程:从集合(数据容器)中获取(移出)数据,进行运算处理


生产者消费者

你在餐厅吃饼,盘子的容量限制是5,放满了不能放
先有盘子,再有厨师(做一张饼就往盘子放饼),再有你(一张一张吃饼)
盘子是栈Stack,最后放的饼会被最先取走,后入先出

public class Stack {
    private char[]a=new char[5];
    private int index;
    public void push(char c){
        a[index]=c;
        index++;
    }
    public char pop()
    {
        index--;
        char c=a[index];
        return c;
    }
    public boolean isEmpty(){
        return index==0;
    }
    public boolean isFull(){
        return index==5;
    }
}
Stack

生产者线程Producer

import java.util.Random;

public class Producer extends Thread {
    private Stack stack;

    public Producer(Stack stack) {
        this.stack = stack;
    }

    @Override
    public void run() {
        int i = 1;
        while (i <= 50) {
            // a~z 97+0=a 97+1=b 97+25=z; 97+[0,26)
            char c = (char) ('a' + new Random().nextInt(26));
            synchronized (stack) {
                // 判断是否满
                while (stack.isFull()) {
                    try {
                        // 暂停,在栈对象上等待,收到通知后会醒过来继续执行
                        stack.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 继续
                }
                stack.push(c);
                System.out.println("压入(烘烤)<--" + c + "饼");
                // 通知在栈对象上等待的线程
                stack.notifyAll();

            }
            i++;
        }
    }
}

消费者线程Consumer

public class Consumer extends Thread {
    private Stack stack;

    public Consumer(Stack stack) {
        this.stack = stack;
    }

    @Override
    public void run() {
        int i = 1;
        while (i <= 50) {
            synchronized (stack) {
                while (stack.isEmpty()) {
                    try {
                        stack.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                char c = stack.pop();
                System.out.println("弹出(吃掉)-->" + c + "饼");
                stack.notifyAll();
            }
            i++;
        }
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        Stack stack=new Stack();
        Producer p = new Producer(stack);
        Consumer c = new Consumer(stack);
        p.start();
        c.start();
    }
}

运行结果

压入(烘烤)<--m饼
压入(烘烤)<--v饼
压入(烘烤)<--e饼
压入(烘烤)<--n饼
压入(烘烤)<--t饼
弹出(吃掉)-->t饼
弹出(吃掉)-->n饼
弹出(吃掉)-->e饼
弹出(吃掉)-->v饼
弹出(吃掉)-->m饼
压入(烘烤)<--f饼
弹出(吃掉)-->f饼
压入(烘烤)<--j饼
弹出(吃掉)-->j饼
压入(烘烤)<--b饼
弹出(吃掉)-->b饼
压入(烘烤)<--j饼
压入(烘烤)<--r饼
压入(烘烤)<--o饼
压入(烘烤)<--x饼
压入(烘烤)<--f饼
弹出(吃掉)-->f饼
弹出(吃掉)-->x饼
弹出(吃掉)-->o饼
弹出(吃掉)-->r饼
弹出(吃掉)-->j饼
压入(烘烤)<--q饼
压入(烘烤)<--h饼
压入(烘烤)<--d饼
压入(烘烤)<--l饼
压入(烘烤)<--m饼
弹出(吃掉)-->m饼
弹出(吃掉)-->l饼
弹出(吃掉)-->d饼
弹出(吃掉)-->h饼
弹出(吃掉)-->q饼
压入(烘烤)<--x饼
压入(烘烤)<--m饼
压入(烘烤)<--l饼
压入(烘烤)<--t饼
压入(烘烤)<--o饼
弹出(吃掉)-->o饼
弹出(吃掉)-->t饼
弹出(吃掉)-->l饼
弹出(吃掉)-->m饼
弹出(吃掉)-->x饼
压入(烘烤)<--x饼
弹出(吃掉)-->x饼
压入(烘烤)<--v饼
弹出(吃掉)-->v饼
压入(烘烤)<--k饼
压入(烘烤)<--k饼
压入(烘烤)<--k饼
压入(烘烤)<--i饼
压入(烘烤)<--m饼
弹出(吃掉)-->m饼
弹出(吃掉)-->i饼
弹出(吃掉)-->k饼
弹出(吃掉)-->k饼
弹出(吃掉)-->k饼
压入(烘烤)<--z饼
弹出(吃掉)-->z饼
压入(烘烤)<--v饼
压入(烘烤)<--v饼
压入(烘烤)<--l饼
压入(烘烤)<--f饼
压入(烘烤)<--e饼
弹出(吃掉)-->e饼
弹出(吃掉)-->f饼
弹出(吃掉)-->l饼
弹出(吃掉)-->v饼
弹出(吃掉)-->v饼
压入(烘烤)<--d饼
压入(烘烤)<--y饼
压入(烘烤)<--o饼
压入(烘烤)<--m饼
压入(烘烤)<--n饼
弹出(吃掉)-->n饼
弹出(吃掉)-->m饼
弹出(吃掉)-->o饼
弹出(吃掉)-->y饼
弹出(吃掉)-->d饼
压入(烘烤)<--r饼
压入(烘烤)<--w饼
压入(烘烤)<--k饼
压入(烘烤)<--v饼
压入(烘烤)<--o饼
弹出(吃掉)-->o饼
弹出(吃掉)-->v饼
弹出(吃掉)-->k饼
弹出(吃掉)-->w饼
弹出(吃掉)-->r饼
压入(烘烤)<--l饼
压入(烘烤)<--u饼
压入(烘烤)<--q饼
压入(烘烤)<--v饼
弹出(吃掉)-->v饼
弹出(吃掉)-->q饼
弹出(吃掉)-->u饼
弹出(吃掉)-->l饼

等待和通知
没有数据时,消费者等待
数据存满时,生产者等待
生产者放入数据,发出通知notifyAll();
消费者取数据,发出通知notifyAll();
Object的方法-等待方法和通知方法
wait()
线程在调用的对象上等待
notify()
在指定对象上发出通知,通知在该对象上所有线程中的一个
如:a.notify()
notifyAll()
通知所有等待的线程

数据存满,生产者等待,消费者敲盘子间接通知

生产者挂在盘子的钩子上等待

没有数据,消费者等待,生产者敲盘子间接通知

等待和通知方法必须在同步代码块内执行

synchronized (对象){
      等待方法或通知方法
}

wait()外面,通常是循环条件判断

while(stack.isFull()){
    try {
        stack.wait();
} catch (InterruptedException e) {
e.printStackTrace();
  }
}

等待和通知方法,必须通过加锁的对象调用
如果不写,会抛监视器异常

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.notifyAll(Native Method)

你可能感兴趣的:(生产者、消费者模型——线程间的通信方式)