Java并发编程深入学习——生产者-消费者模式多种实现方式

来源:互联网 发布:易语言取中间文本源码 编辑:程序博客网 时间:2024/05/17 08:22

问题介绍

  生产者消费者模型是经典的同步问题。问题大致如下:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权。因为生产者如果不释放对临界资源的占用权,那么消费者就无法消费队列中的商品,就不会让队列有空间,那么生产者就会一直无限等待下去。因此,一般情况下,当队列满时,会让生产者交出对临界资源的占用权,并进入挂起状态。然后等待消费者消费了商品,然后消费者通知生产者队列有空间了。同样地,当队列空时,消费者也必须等待,等待生产者通知它队列中有商品了。这种互相通信的过程就是线程间的协作。

下面总结了三种方式来实现一个消费者/生产者模型.

1.wait/notify模式

/** * wait and notify * 生产者和消费者问题 * * @author bridge */public class test1 {    public static void main(String[] args) {        Resource resource = new Resource();        //生产者线程        ProducerThread p = new ProducerThread(resource);        //多个消费者        ConsumerThread c1 = new ConsumerThread(resource);        ConsumerThread c2 = new ConsumerThread(resource);        ConsumerThread c3 = new ConsumerThread(resource);        p.start();        c1.start();        c2.start();        c3.start();    }}class ProducerThread extends Thread {    private Resource resource;    public ProducerThread(Resource resource) {        this.resource = resource;        //setName("生产者");    }    public void run() {        while (true) {            try {                Thread.sleep((long) (1000 * Math.random()));            } catch (InterruptedException e) {                e.printStackTrace();            }            resource.add();        }    }}class ConsumerThread extends Thread {    private Resource resource;    public ConsumerThread(Resource resource) {        this.resource = resource;        //setName("消费者");    }    public void run() {        while (true) {            try {                Thread.sleep((long) (1000 * Math.random()));            } catch (InterruptedException e) {                e.printStackTrace();            }            resource.remove();        }    }}/** * 公共资源类 */class Resource {    //当前资源数量    private int num = 0;    //资源池中允许存放的资源数    private int size = 10;    /***     * 向资源池中添加资源     */    public synchronized void add() {        if (num < size) {            num++;            System.out.println(Thread.currentThread().getName() + "生产一件资源,当前资源池有" + num + "个");            notifyAll();        } else {            try {                wait();                System.out.println(Thread.currentThread().getName() + "线程进入等待");            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    /**     * 从资源池中取走资源     */    public synchronized void remove() {        if (num > 0) {            num--;            System.out.println("消费者" + Thread.currentThread().getName() + "消耗一件资源," + "当前资源池有" + num + "个");            notifyAll();        } else {            try {                wait();                System.out.println(Thread.currentThread().getName() + "线程进入等待");            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

2.Lock condition模式

package ProducerAndConsumer.p2;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** * lock和condition解法 * 生产者和消费者问题 * * @author bridge */public class test2 {    public static void main(String[] args) {        Lock lock = new ReentrantLock();        Condition pCondition = lock.newCondition();        Condition cCondition = lock.newCondition();        Resource resource = new Resource(lock, pCondition, cCondition);        //生产者线程        ProducerThread p = new ProducerThread(resource);        //多个消费者        ConsumerThread c1 = new ConsumerThread(resource);        ConsumerThread c2 = new ConsumerThread(resource);        ConsumerThread c3 = new ConsumerThread(resource);        p.start();        c1.start();//        c2.start();//        c3.start();    }}/** * 生产者线程 */class ProducerThread extends Thread {    private Resource resource;    public ProducerThread(Resource resource) {        this.resource = resource;        setName("生产者");    }    public void run() {        while (true) {            try {                Thread.sleep((long) (1000 * Math.random()));            } catch (InterruptedException e) {                e.printStackTrace();            }            resource.add();        }    }}/** * 消费者线程 */class ConsumerThread extends Thread {    private Resource resource;    public ConsumerThread(Resource resource) {        this.resource = resource;        //setName("消费者");    }    public void run() {        while (true) {            try {                Thread.sleep((long) (1000 * Math.random()));            } catch (InterruptedException e) {                e.printStackTrace();            }            resource.remove();        }    }}/** * 公共资源类 */class Resource {    //当前资源数量    private int num = 0;    //资源池中允许存放的资源数    private int size = 10;    private Lock lock;    private Condition pCondition;    private Condition cCondition;    public Resource(Lock lock, Condition pCondition, Condition cCondition) {        this.lock = lock;        this.pCondition = pCondition;        this.cCondition = cCondition;    }    /***     * 向资源池中添加资源     */    public void add() {        lock.lock();        try {            if (num < size) {                num++;                System.out.println(Thread.currentThread().getName() + "生产一件资源,当前资源池有" + num + "个");                //唤醒等待的消费者                cCondition.signalAll();            } else {                //使生产者等待                pCondition.await();                System.out.println(Thread.currentThread().getName() + "线程进入等待");            }        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            lock.unlock();        }    }    /**     * 从资源池中取走资源     */    public void remove() {        lock.lock();        try {            if (num > 0) {                num--;                System.out.println("消费者" + Thread.currentThread().getName() + "消耗一件资源," + "当前资源池有" + num + "个");                pCondition.signalAll();  //唤醒等待的生产者            } else {                try {                    cCondition.await();                    //使消费者等待                    System.out.println(Thread.currentThread().getName() + "线程进入等待");                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        } finally {            lock.unlock();        }    }}

3.阻塞队列模式

package ProducerAndConsumer.p3;import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;/** * 阻塞队列解法 * 生产者和消费者问题 * * @author bridge */public class test3 {    public static void main(String[] args) {        Resource resource = new Resource();        //生产者线程        ProducerThread p = new ProducerThread(resource);        //多个消费者        ConsumerThread c1 = new ConsumerThread(resource);        ConsumerThread c2 = new ConsumerThread(resource);        ConsumerThread c3 = new ConsumerThread(resource);        p.start();        c1.start();        // c2.start();        // c3.start();    }}class ProducerThread extends Thread {    private Resource resource;    public ProducerThread(Resource resource) {        this.resource = resource;        //setName("生产者");    }    public void run() {        while (true) {            try {                Thread.sleep((long) (1000 * Math.random()));            } catch (InterruptedException e) {                e.printStackTrace();            }            resource.add();        }    }}class ConsumerThread extends Thread {    private Resource resource;    public ConsumerThread(Resource resource) {        this.resource = resource;        //setName("消费者");    }    public void run() {        while (true) {            try {                Thread.sleep((long) (1000 * Math.random()));            } catch (InterruptedException e) {                e.printStackTrace();            }            resource.remove();        }    }}/** * 公共资源类 */class Resource {    private BlockingQueue resourceQueue = new LinkedBlockingQueue(10);    /***     * 向资源池中添加资源     */    public void add() {        try {            resourceQueue.put(1);            System.out.println("生产者" + Thread.currentThread().getName() + "生产一件资源," + "当前资源池有" + resourceQueue.size() + "个资源");        } catch (InterruptedException e) {            e.printStackTrace();        }    }    /**     * 从资源池中取走资源     */    public void remove() {        try {            resourceQueue.take();            System.out.println("消费者" + Thread.currentThread().getName() + "消耗一件资源," + "当前资源池有" + resourceQueue.size() + "个资源");        } catch (InterruptedException e) {            e.printStackTrace();        }    }}
0 0
原创粉丝点击