深入生产者与消费者模式

来源:互联网 发布:采集助手数据库 编辑:程序博客网 时间:2024/05/16 23:48

前提
本示例是生产者向堆栈中 List 对象中放入数据,使消费者从 List 堆栈中取出数据。List 最大容量是 1

一生产一消费——操作栈

MyStack代码

import java.util.ArrayList;import java.util.List;public class MyStack {    private List list = new ArrayList();    synchronized public void push(){        try {            if(list.size() == 1){                this.wait();            }            list.add("anyString = "+ Math.random());            this.notify();            System.out.println("push = "+ list.size());        } catch (InterruptedException e) {            e.printStackTrace();        }    }    synchronized public String pop(){        String returnValue = "";        try {            if(list.size() == 0){                this.wait();            }            returnValue = list.get(0)+"";            list.remove(0);            this.notify();            System.out.println("pop = "+ list.size());        } catch (InterruptedException e) {            e.printStackTrace();        }        return returnValue;    }}

MainThread代码

public class mainThread {    public static void main(String[] args) {        MyStack myStack = new MyStack();        ThreadP pThread = new ThreadP(myStack);        ThreadC cThread = new ThreadC(myStack);        pThread.start();        cThread.start();    }}class ThreadP extends Thread {    private MyStack myStack;    public ThreadP(MyStack myStack) {        super();        this.myStack = myStack;    }    public void run(){        while(true){            myStack.push();        }    }}class ThreadC extends Thread {    private MyStack myStack;    public ThreadC(MyStack myStack) {        super();        this.myStack = myStack;    }    public void run(){        while(true){            myStack.pop();        }    }}

输出结果
image_1at13hj9u991ol91oas10igome9.png-5kB

程序运行结果是 size() 不会大于1,通过生产者/消费者模式,两个操作交替进行

一生产与多消费——操作栈:解决 wait 条件改变与假死

启动多个消费者,只需要在 mainThread 中启动多个消费者线程,MyStack 不用更改。代码如下:

public class mainThread {    public static void main(String[] args) {        MyStack myStack = new MyStack();        ThreadP pThread = new ThreadP(myStack);        ThreadC cThread1 = new ThreadC(myStack);        ThreadC cThread2 = new ThreadC(myStack);        pThread.start();        cThread1.start();        cThread2.start();    }}class ThreadP extends Thread {    private MyStack myStack;    public ThreadP(MyStack myStack) {        super();        this.myStack = myStack;    }    public void run(){        while(true){            myStack.push();        }    }}class ThreadC extends Thread {    private MyStack myStack;    public ThreadC(MyStack myStack) {        super();        this.myStack = myStack;    }    public void run(){        while(true){            myStack.pop();        }    }}

运行结果如下所示:
image_1at13r9nj1qnf1m3m1je3fe518a2m.png-57.4kB

此问题的出现就是因为 MyStack 类中使用了 if 语句作为条件判断。
image_1at142keu3dg8ll1cfokgs87u13.png-2.8kB
image_1at142td3j9g1b0l1h2113ti1pn71g.png-3.4kB
因为条件发生改变的时候并没有得到及时的响应,所以多个呈 wait 状态的线程被召唤,继而执行 list.remove(0) 代码出现异常。解决策略就是讲 if 更换为 while 语句。

image_1at149a8sp121bm11u3pk3v157d1t.png-61.9kB

解决办法当然还是采用 notifyAll()。将 MyStack 中两处 notify 变更为 notifyAll() 后即可。

多生产与一消费)——操作栈

启动多个生产者,只需要在 mainThread 中启动多个生产者线程,MyStack 不用更改。代码如下:

public class mainThread {    public static void main(String[] args) {        MyStack myStack = new MyStack();        ThreadP pThread1 = new ThreadP(myStack);        ThreadP pThread2 = new ThreadP(myStack);        ThreadC cThread = new ThreadC(myStack);        pThread1.start();        pThread2.start();        cThread.start();    }}class ThreadP extends Thread {    private MyStack myStack;    public ThreadP(MyStack myStack) {        super();        this.myStack = myStack;    }    public void run(){        while(true){            myStack.push();        }    }}class ThreadC extends Thread {    private MyStack myStack;    public ThreadC(MyStack myStack) {        super();        this.myStack = myStack;    }    public void run(){        while(true){            myStack.pop();        }    }}

采用上面 “一生产/多消费”模式依旧可以唱功运行。

多生产者与多消费者:操作栈

启动多个生产者和多个消费者,只需要在 mainThread 中启动多个生产者线程和多个消费者线程,MyStack 不用更改。代码如下:

public class mainThread {    public static void main(String[] args) {        MyStack myStack = new MyStack();        ThreadP pThread1 = new ThreadP(myStack);        ThreadP pThread2 = new ThreadP(myStack);        ThreadC cThread = new ThreadC(myStack);        pThread1.start();        pThread2.start();        cThread.start();    }}class ThreadP extends Thread {    private MyStack myStack;    public ThreadP(MyStack myStack) {        super();        this.myStack = myStack;    }    public void run(){        while(true){            myStack.push();        }    }}class ThreadC extends Thread {    private MyStack myStack;    public ThreadC(MyStack myStack) {        super();        this.myStack = myStack;    }    public void run(){        while(true){            myStack.pop();        }    }}

image_1at14o1tob66pfl1mcm1p7d1bh02a.png-51.8kB

0 0