生产者消费者

来源:互联网 发布:淘宝掌柜名能改吗 编辑:程序博客网 时间:2024/05/22 01:36

生产者和消费者是一种经典的供求案例,生产者和消费者线程之间的关系涉及线程之间的交互。生产者线程产生的数据项,将来会被消费者消费,每个生产出来的数据会被保存在一个共享的仓库中。

假设线程以不同的速度进行,那么将会导致消费者可能获取到还未生产的数据,生产者也有可能在消费者还未取走前一条数据的前提下继续生产,这样就会造成混乱。

为了克服这种混乱,生产者线程必须等待,知道消费者取走之后通知生产者,等待解除,可以生产。如果生产者未生产数据,消费者就要一直等待,直到生产者生产完毕,唤醒消费者线程,取走生产好的数据。

生产者消费者
以下为代码实现:

package my_application;public class ProducerConsumer {    public static void main(String[] args) {        ShareStorage s = new ShareStorage();        new Producer(s).start();        new Consumer(s).start();    }}class ShareStorage{    private char c;        //此实例变量跟踪两个条件,生产者等待消费者消费一个数据,消费者等待生产者生产一个数据    private volatile boolean flag = true;    synchronized void setShareData(char c){        while (!flag) {//消费者未取走,则生产者等待            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        this.c = c;        flag = false;//设置标志位为false,告诉消费者可以消费,此时生产者等待        notify();    }    synchronized char getShareData(){        while (flag) {//flag = true ,表示消费者等待,此时生产者生产            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        flag = true;        notify();        return c;    }}class Producer extends Thread{    private final ShareStorage shareStorage;    Producer(ShareStorage shareStorage){        this.shareStorage = shareStorage;    }    @Override    public void run() {        for (char ch = 'A'; ch < 'Z'; ch++) {            shareStorage.setShareData(ch);            System.out.println(ch + ",生产者生产");        }    }}class Consumer extends Thread{    private final ShareStorage shareStorage;    Consumer(ShareStorage shareStorage){        this.shareStorage = shareStorage;    }    @Override    public void run() {        char ch;        do {            ch = shareStorage.getShareData();            System.out.println(ch + ",消费者消费");        } while (ch != 'Z');    }}

此时的输出结果可能为:

O,生产者生产O,消费者消费P,生产者生产P,消费者消费

或者

A,生产者生产B,生产者生产A,消费者消费B,消费者消费

这样的输出并不表示消费者和生产者线程没有同步,这是因为setShareData(),getShareData()之后的输出没有被同步造成的结果,为了解决这个问题,加上同步块就可以完美解决这个问题了。见下面修改后的代码:

package my_application;public class ProducerConsumer {    public static void main(String[] args) {        ShareStorage s = new ShareStorage();        new Producer(s).start();        new Consumer(s).start();    }}class ShareStorage{    private char c;    private volatile boolean flag = true;//写入取走标记    synchronized void setShareData(char c){        while (!flag) {//消费者未取走,则生产者等待            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        this.c = c;        flag = false;//设置标志位为false,告诉消费者可以消费,此时生产者等待        notify();    }    synchronized char getShareData(){        while (flag) {//flag = true ,表示消费者等待,此时生产者生产            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        flag = true;        notify();        return c;    }}class Producer extends Thread{    private final ShareStorage shareStorage;    Producer(ShareStorage shareStorage){        this.shareStorage = shareStorage;    }    @Override    public void run() {        for (char ch = 'A'; ch < 'Z'; ch++) {            synchronized (shareStorage) {                shareStorage.setShareData(ch);                System.out.println(ch + ",生产者生产");            }        }    }}class Consumer extends Thread{    private final ShareStorage shareStorage;    Consumer(ShareStorage shareStorage){        this.shareStorage = shareStorage;    }    @Override    public void run() {        char ch;        do {            synchronized (shareStorage) {                ch = shareStorage.getShareData();                System.out.println(ch + ",消费者消费");            }        } while (ch != 'Z');    }}

输出结果:

A,生产者生产A,消费者消费B,生产者生产B,消费者消费C,生产者生产C,消费者消费D,生产者生产D,消费者消费E,生产者生产E,消费者消费...
原创粉丝点击