生产者消费者模式

来源:互联网 发布:淘宝买电脑可靠吗 编辑:程序博客网 时间:2024/05/21 07:10

生产者、消费者模式

1、一生产与一消费,操作值

package me.mymilkbottles.Study04;import java.util.Date;/** * Created by Administrator on 2017/07/16 8:29. */public class OnePOneCValue {    public static void main(String[] args) {        P1 p1 = new P1("hello");        C1 c1 = new C1("hello");        MyThreadC1 myThreadC1 = new MyThreadC1(c1);        myThreadC1.start();        MyThreadP1 myThreadP1 = new MyThreadP1(p1);        myThreadP1.start();//        for (int i = 0; i < 10; ++i) {//            MyThreadC1 myThreadC1 = new MyThreadC1(c1);//            myThreadC1.start();//            MyThreadP1 myThreadP1 = new MyThreadP1(p1);//            myThreadP1.start();//        }    }}class ValueObject {    public static String value = null;}class P1 {    private String lock;    public P1(String lock) {        this.lock = lock;    }    public void set() throws InterruptedException {        synchronized (lock) {            if (ValueObject.value != null) {                lock.wait();            }            ValueObject.value = String.valueOf(System.nanoTime());            System.out.println("set " + ValueObject.value);            lock.notify();        }    }}class C1 {    private String lock;    public C1(String lock) {        this.lock = lock;    }    public void get() throws InterruptedException {        synchronized (lock) {            if (ValueObject.value == null) {                lock.wait();            }            System.out.println("get " + ValueObject.value);            ValueObject.value = null;            lock.notify();        }    }}class MyThreadP1 extends Thread {    private P1 p1;    public MyThreadP1(P1 p1) {        this.p1 = p1;    }    @Override    public void run() {        while (true) {            try {                p1.set();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}class MyThreadC1 extends Thread {    private C1 c1;    public MyThreadC1(C1 c1) {        this.c1 = c1;    }    @Override    public void run() {        while (true) {            try {                c1.get();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

如果在此基础上,设计出多个生产者和多个消费者,那么在运行的过程中极有可能出现假死的情况,也就是所有的线程都呈WAITING等待状态。

2、多生产与多消费:操作值-假死

package me.mymilkbottles.Study04;import java.util.Date;/** * Created by Administrator on 2017/07/16 8:29. */public class OnePOneCValue {    public static void main(String[] args) {        P1 p1 = new P1("hello");        C1 c1 = new C1("hello");//        MyThreadC1 myThreadC1 = new MyThreadC1(c1);//        myThreadC1.start();//        MyThreadP1 myThreadP1 = new MyThreadP1(p1);//        myThreadP1.start();        for (int i = 0; i < 10; ++i) {            MyThreadC1 myThreadC1 = new MyThreadC1(c1);            myThreadC1.setName("消费者" + i);            myThreadC1.start();            MyThreadP1 myThreadP1 = new MyThreadP1(p1);            myThreadP1.setName("生产者" + i);            myThreadP1.start();        }    }}class ValueObject {    public static String value = null;}class P1 {    private String lock;    public P1(String lock) {        this.lock = lock;    }    public void set() throws InterruptedException {        synchronized (lock) {            while (ValueObject.value != null) {                lock.wait();            }            ValueObject.value = String.valueOf(System.nanoTime());            System.out.println("set " + ValueObject.value);            lock.notify();        }    }}class C1 {    private String lock;    public C1(String lock) {        this.lock = lock;    }    public void get() throws InterruptedException {        synchronized (lock) {            while (ValueObject.value == null) {                lock.wait();            }            System.out.println("get " + ValueObject.value);            ValueObject.value = null;            lock.notify();        }    }}class MyThreadP1 extends Thread {    private P1 p1;    public MyThreadP1(P1 p1) {        this.p1 = p1;    }    @Override    public void run() {        while (true) {            try {                p1.set();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}class MyThreadC1 extends Thread {    private C1 c1;    public MyThreadC1(C1 c1) {        this.c1 = c1;    }    @Override    public void run() {        while (true) {            try {                c1.get();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

我们可以打印当前线程的状态信息:

try {    Thread.sleep(6000);} catch (InterruptedException e) {    e.printStackTrace();}Thread[] threads = new Thread[Thread.activeCount()];Thread.currentThread().getThreadGroup().enumerate(threads);for (Thread thread : threads) {    System.out.println(thread.getName() + " " + thread.getState());}

打印结果如下:

main RUNNABLEMonitor Ctrl-Break RUNNABLE消费者0 WAITING生产者0 WAITING消费者1 WAITING生产者1 WAITING消费者2 WAITING生产者2 WAITING消费者3 WAITING生产者3 WAITING消费者4 WAITING生产者4 WAITING消费者5 WAITING生产者5 WAITING消费者6 WAITING生产者6 WAITING消费者7 WAITING生产者7 WAITING消费者8 WAITING生产者8 WAITING消费者9 WAITING生产者9 WAITING

可以看到,所有的线程都在WAITING状态,这是因为虽然我们使用了notify通知,但是不能保证notify唤醒的就一定是异类,如果唤醒的是同类,比如:生产者唤醒了生产者,那么这样的情况累积下来,就会导致所有的线程都在等待,程序最后也成了假死状态。

3、多生产与多消费:操作值

为了避免假死的情况,解决的办法就是将notify改成notifyAll即可。

package me.mymilkbottles.Study04;import java.util.Date;/** * Created by Administrator on 2017/07/16 8:29. */public class OnePOneCValue {    public static void main(String[] args) {        P1 p1 = new P1("hello");        C1 c1 = new C1("hello");//        MyThreadC1 myThreadC1 = new MyThreadC1(c1);//        myThreadC1.start();//        MyThreadP1 myThreadP1 = new MyThreadP1(p1);//        myThreadP1.start();        for (int i = 0; i < 10; ++i) {            MyThreadC1 myThreadC1 = new MyThreadC1(c1);            myThreadC1.setName("消费者" + i);            myThreadC1.start();            MyThreadP1 myThreadP1 = new MyThreadP1(p1);            myThreadP1.setName("生产者" + i);            myThreadP1.start();        }        try {            Thread.sleep(6000);        } catch (InterruptedException e) {            e.printStackTrace();        }        Thread[] threads = new Thread[Thread.activeCount()];        Thread.currentThread().getThreadGroup().enumerate(threads);        for (Thread thread : threads) {            System.out.println(thread.getName() + " " + thread.getState());        }    }}class ValueObject {    public static String value = null;}class P1 {    private String lock;    public P1(String lock) {        this.lock = lock;    }    public void set() throws InterruptedException {        synchronized (lock) {            while (ValueObject.value != null) {                lock.wait();            }            ValueObject.value = String.valueOf(System.nanoTime());            System.out.println("set " + ValueObject.value);            lock.notifyAll();        }    }}class C1 {    private String lock;    public C1(String lock) {        this.lock = lock;    }    public void get() throws InterruptedException {        synchronized (lock) {            while (ValueObject.value == null) {                lock.wait();            }            System.out.println("get " + ValueObject.value);            ValueObject.value = null;            lock.notifyAll();        }    }}class MyThreadP1 extends Thread {    private P1 p1;    public MyThreadP1(P1 p1) {        this.p1 = p1;    }    @Override    public void run() {        while (true) {            try {                p1.set();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}class MyThreadC1 extends Thread {    private C1 c1;    public MyThreadC1(C1 c1) {        this.c1 = c1;    }    @Override    public void run() {        while (true) {            try {                c1.get();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

4、一生产与一消费:操作栈

package me.mymilkbottles.Study04;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2017/07/16 9:27. */public class OnePOneCStack {    public static void main(String[] args) {        P2 p2 = new P2("hello");        C2 c2 = new C2("hello");        MyThreadC2 myThreadC2 = new MyThreadC2(c2);        myThreadC2.start();        MyThreadP2 myThreadP2 = new MyThreadP2(p2);        myThreadP2.start();    }}class ListObject {    public static List<String> list = new ArrayList<>();}class P2 {    private String lock;    public P2(String lock) {        this.lock = lock;    }    public void set() throws InterruptedException {        synchronized (lock) {            if (ListObject.list.size() == 1) {                lock.wait();            }            String value = String.valueOf(System.nanoTime());            ListObject.list.add(value);            System.out.println("set " + value);            lock.notify();        }    }}class C2 {    private String lock;    public C2(String lock) {        this.lock = lock;    }    public void get() throws InterruptedException {        synchronized (lock) {            if (ListObject.list.size() == 0) {                lock.wait();            }            System.out.println("get " + ListObject.list.get(0));            ListObject.list.remove(0);            lock.notify();        }    }}class MyThreadP2 extends Thread {    private P2 p2;    public MyThreadP2(P2 p2) {        this.p2 = p2;    }    @Override    public void run() {        while (true) {            try {                p2.set();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}class MyThreadC2 extends Thread {    private C2 c2;    public MyThreadC2(C2 c2) {        this.c2 = c2;    }    @Override    public void run() {        while (true) {            try {                c2.get();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

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

package me.mymilkbottles.Study04;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2017/07/16 9:27. */public class OnePOneCStack {    public static void main(String[] args) {        P2 p2 = new P2("hello");        C2 c2 = new C2("hello");        MyThreadP2 myThreadP2 = new MyThreadP2(p2);        myThreadP2.start();        for (int i = 0; i < 10; ++i) {            MyThreadC2 myThreadC2 = new MyThreadC2(c2);            myThreadC2.start();        }    }}class ListObject {    public static List<String> list = new ArrayList<>();}class P2 {    private String lock;    public P2(String lock) {        this.lock = lock;    }    public void set() throws InterruptedException {        synchronized (lock) {            if (ListObject.list.size() == 1) {                lock.wait();            }            String value = String.valueOf(System.nanoTime());            ListObject.list.add(value);            System.out.println("set " + value);            lock.notify();        }    }}class C2 {    private String lock;    public C2(String lock) {        this.lock = lock;    }    public void get() throws InterruptedException {        synchronized (lock) {            if (ListObject.list.size() == 0) {                lock.wait();            }            System.out.println("get " + ListObject.list.get(0));            ListObject.list.remove(0);            lock.notify();        }    }}class MyThreadP2 extends Thread {    private P2 p2;    public MyThreadP2(P2 p2) {        this.p2 = p2;    }    @Override    public void run() {        while (true) {            try {                p2.set();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}class MyThreadC2 extends Thread {    private C2 c2;    public MyThreadC2(C2 c2) {        this.c2 = c2;    }    @Override    public void run() {        while (true) {            try {                c2.get();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}/*执行结果:Exception in thread "Thread-7" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0    at java.util.ArrayList.rangeCheck(ArrayList.java:635)    at java.util.ArrayList.get(ArrayList.java:411)    at me.mymilkbottles.Study04.C2.get(OnePOneCStack.java:56)    at me.mymilkbottles.Study04.MyThreadC2.run(OnePOneCStack.java:89)set 5055921991938get 5055921991938*/

可以看到结果出现了IndexOutOfBoundsException,原因是因为条件发生改变的时候并没有得到及时的响应,所以多个呈wait状态的线程被唤醒,继而执行remove的时候越界。

解决的方法就是将if改为while。

package me.mymilkbottles.Study04;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2017/07/16 9:27. */public class OnePOneCStack {    public static void main(String[] args) {        P2 p2 = new P2("hello");        C2 c2 = new C2("hello");        MyThreadP2 myThreadP2 = new MyThreadP2(p2);        myThreadP2.setName("生产者1");        myThreadP2.start();        for (int i = 0; i < 10; ++i) {            MyThreadC2 myThreadC2 = new MyThreadC2(c2);            myThreadC2.setName("消费者" + i);            myThreadC2.start();        }        try {            Thread.sleep(2000);        } catch (InterruptedException e) {            e.printStackTrace();        }        Thread[] threads = new Thread[Thread.activeCount()];        Thread.currentThread().getThreadGroup().enumerate(threads);        for (Thread thread : threads) {            System.out.println(thread.getName() + " : " + thread.getState());        }    }}class ListObject {    public static List<String> list = new ArrayList<>();}class P2 {    private String lock;    public P2(String lock) {        this.lock = lock;    }    public void set() throws InterruptedException {        synchronized (lock) {            while (ListObject.list.size() == 1) {                lock.wait();            }            String value = String.valueOf(System.nanoTime());            ListObject.list.add(value);            System.out.println("set " + value);            lock.notify();        }    }}class C2 {    private String lock;    public C2(String lock) {        this.lock = lock;    }    public void get() throws InterruptedException {        synchronized (lock) {            while (ListObject.list.size() == 0) {                lock.wait();            }            System.out.println("get " + ListObject.list.get(0));            ListObject.list.remove(0);            lock.notify();        }    }}class MyThreadP2 extends Thread {    private P2 p2;    public MyThreadP2(P2 p2) {        this.p2 = p2;    }    @Override    public void run() {        while (true) {            try {                p2.set();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}class MyThreadC2 extends Thread {    private C2 c2;    public MyThreadC2(C2 c2) {        this.c2 = c2;    }    @Override    public void run() {        while (true) {            try {                c2.get();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}/*执行结果:set 5437922928284get 5437922928284set 5437923471854get 5437923471854main : RUNNABLEMonitor Ctrl-Break : RUNNABLE生产者1 : WAITING消费者0 : WAITING消费者1 : WAITING消费者2 : WAITING消费者3 : WAITING消费者4 : WAITING消费者5 : WAITING消费者6 : WAITING消费者7 : WAITING消费者8 : WAITING消费者9 : WAITING*/

可以看到又和上面的情况(唤醒同类)类似了,那么我们使用notifyAll即可解决。

6、多生产与一消费:操作栈

这种情况和一生产和多消费是类似的。

7、多生产与多消费:操作栈

这种情况和上面两种的情况也是类似的。