java实现生产者消费者模式

来源:互联网 发布:淘宝扫码付款被骗 编辑:程序博客网 时间:2024/06/01 19:56

生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个具有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经放入产品的缓冲区中再次投放产品。

使用synchronized关键字实现线程同步

在使用wait()和notifyAll()方法时,应注意将wait()方法放入循环中,否则会产生虚假唤醒问题。

/** * Created by 吴海飞 on 2017-1-23. */public class TestProductAndConsumer {    public static void main(String[] args){        Clerk clerk = new Clerk();        Productor pro = new Productor(clerk);        Consumer consumer = new Consumer(clerk);        new Thread(pro,"生产者A").start();        new Thread(consumer,"消费者B").start();    }}/** * 店员,可以进货与销售货物 */class Clerk{    private int product = 0;    /**     * 进货的方法     */    public synchronized void get(){        while (product>=1){//为了避免虚假唤醒问题,应该总是使用在循环中            System.out.println("产品已满!");            try {                this.wait();//等待            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.println(Thread.currentThread().getName() + ":" + ++product);        this.notifyAll();//唤醒线程    }    /**     * 销售的方法     */    public synchronized void sale(){        while (product<=0){//为避免虚假唤醒,应该总是始终使用在循环中            System.out.println("缺货……");            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.println(Thread.currentThread().getName() + ":"+ --product);        this.notifyAll();    }}/** * 生产者 */class Productor implements Runnable{    private Clerk clerk;    public Productor(Clerk clerk){        this.clerk = clerk;    }    @Override    public void run() {        for (int i = 0; i < 10; i++){            try {                Thread.sleep(200);            } catch (InterruptedException e) {                e.printStackTrace();            }            clerk.get();        }    }}/** * 消费者 */class Consumer implements Runnable{    private Clerk clerk;    public Consumer(Clerk clerk){        this.clerk = clerk;    }    @Override    public void run() {        for (int i = 0; i < 10; i++){            clerk.sale();        }    }}

使用同步锁实现线程同步问题

使用同步锁时应注意lock()与unlock()方法的同步使用。

import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** * 使用ReentrantLock实现生产者消费者问题 * Created by 吴海飞 on 2017-1-23. */public class TestReentrantLock {    public static void main(String[] args){        Clerk clerk = new Clerk();        Productor pro = new Productor(clerk);        Consumer consumer = new Consumer(clerk);        new Thread(pro,"生产者A").start();        new Thread(consumer,"消费者B").start();        new Thread(pro,"生产者C").start();        new Thread(consumer,"消费者D").start();    }}class Clerk{    private Lock lock = new ReentrantLock();//获取同步锁    private Condition condition = lock.newCondition();    private int product = 0;/** * 进货的方法 */    public void get(){        lock.lock();//打开锁        try{            while (product>=1){//为了避免虚假唤醒问题,应该总是使用在循环中                System.out.println("产品已满!");                try {                    condition.await();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            System.out.println(Thread.currentThread().getName() + ":" + ++product);            condition.signalAll();        }finally {            lock.unlock();//关闭锁        }    }/** * 销售的方法 */    public void sale(){        lock.lock();//加锁        try {            while (product<=0){//为避免虚假唤醒,应该总是始终使用在循环中                System.out.println("缺货……");                try {                    condition.await();//等待                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            System.out.println(Thread.currentThread().getName() + ":"+ --product);            condition.signalAll();//唤醒等待        }finally {            lock.unlock();//释放锁        }    }}/** * 生产者 */class Productor implements Runnable{    private Clerk clerk;    public Productor(Clerk clerk){        this.clerk = clerk;    }    @Override    public void run() {        for (int i = 0; i < 10; i++){            try {                Thread.sleep(200);            } catch (InterruptedException e) {                e.printStackTrace();            }            clerk.get();        }    }}/** * 消费者 */class Consumer implements Runnable{    private Clerk clerk;    public Consumer(Clerk clerk){        this.clerk = clerk;    }    @Override    public void run() {        for (int i = 0; i < 10; i++){            clerk.sale();        }    }}
0 0