生产者和消费者三种实现

来源:互联网 发布:网络信号大师 编辑:程序博客网 时间:2024/05/18 09:56

1、syncronized+wait+notify

package com.rrfare.producerconsumer;import java.util.LinkedList;import java.util.Queue;import java.util.Random;public class OrderManager {    // 容器最大值    private static final int MAX_COUNT = 5;    // 容器(这里不使用BlockingQueue,而是使用线程不安全的LinkedList,并结合syncronized保证线程安全)    private Queue<Order> orderQueue = new LinkedList<Order>();    private Random random = new Random();    public static void main(String[] args) {        OrderManager shareObj = new OrderManager();        Thread produceThread = new Thread(new ProducerThread(shareObj));        Thread produceThread2 = new Thread(new ProducerThread(shareObj));        produceThread.start();        produceThread2.start();        Thread consumerThread = new Thread(new ConsumeThread(shareObj));        Thread consumerThread2 = new Thread(new ConsumeThread(shareObj));        consumerThread.start();        consumerThread2.start();    }    public synchronized void addOrder(){        while(orderQueue.size() >= MAX_COUNT){            try {                System.out.println(Thread.currentThread().getName() + "队列已满,待会再生产");                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        int i = random.nextInt(1000);        Order tempOrder = new Order(i,"order"+i);        orderQueue.offer(tempOrder);  // use prefer to add        System.out.println(Thread.currentThread().getName() + "--produce order--" + tempOrder);        notifyAll();    }    public synchronized void takeOrder(){        while(orderQueue.size() < 1){            try {                System.out.println(Thread.currentThread().getName() + "队列已空,等待生产");                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        Order tempOrder = orderQueue.poll(); // use prefer to remove        System.out.println(Thread.currentThread().getName() + "--consume order--" + tempOrder);        notifyAll();    }}class ProducerThread implements Runnable {    private OrderManager orderManager;    public  ProducerThread(OrderManager orderManager) {        this.orderManager = orderManager;    }    @Override    public void run() {        while(true){            orderManager.addOrder();        }    }}class ConsumeThread implements Runnable {    private OrderManager orderManager;    public  ConsumeThread(OrderManager orderManager) {        this.orderManager = orderManager;    }    @Override    public void run() {        while(true){            orderManager.takeOrder();        }    } }

2、BlockingQueue

public class UseBlockQueue {    /**     * 队列元素数量达到指定容量时会阻塞生产者线程,消费者消费数据时,生产者线程又被唤醒     * LinkedBlockingQueue实现中生产者和消费者使用了不同的锁,消费者和生产者可以并发处理队列中数据,因此可以用于高并发应用中     * 注意:默认构造时会创建一个无限大队列,这样如果生产者速度一旦大于消费者,就会导致资源慢慢耗尽,因此构造时最好显式指定容量     */    private static BlockingQueue<Order> orderQueue = new LinkedBlockingQueue<Order>(10);  // BlockingQueue内部实现了同步细节,直接使用很方便    /**     * 内部维护一个定长数组     * ArrayBlockingQueue在生产者放入数据和消费者获取数据,都是共用同一个锁对象,导致生产者和消费者无法并行操作数据     * ArrayBlockingQueue和LinkedBlockingQueue重要区别在于,前者在插入或删除元素时不会产生或销毁任何额外的对象实例,     * 而后者则会生成一个额外的Node对象。这在长时间内需要高效并发地处理大批量数据的系统中,对于GC的影响存在一定的区别     */    private static BlockingQueue<Order> orderQueue2 = new ArrayBlockingQueue<Order>(10);    public static void main(String[] args) {        Thread produceThread = new Thread(new ProducerThread(orderQueue));        Thread consumerThread1 = new Thread(new ConsumerThread(orderQueue));        Thread consumerThread2 = new Thread(new ConsumerThread(orderQueue));        produceThread.start();        consumerThread1.start();        consumerThread2.start();    }}class ConsumerThread implements Runnable {    private BlockingQueue<Order> order_Queue;    public ConsumerThread(BlockingQueue<Order> orderQueue){        this.order_Queue = orderQueue;    }    @Override    public void run() {        while(true){            Order tempOrder = null;            try {                tempOrder = order_Queue.take();            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName()+"--consume order--" + tempOrder);        }    }}class ProducerThread implements Runnable {    private Random random = new Random();    private BlockingQueue<Order> order_Queue;    public  ProducerThread(BlockingQueue<Order> orderQueue){        this.order_Queue = orderQueue;    }    @Override    public void run() {        while(true){            int i = random.nextInt(1000);            Order tempOrder = new Order(i,"order"+i);//          order_Queue.add(tempOrder);   // add和put的区别:前者在队列满之后如果继续添加会抛出异常;后者会进入阻塞状态等待消费者消费腾出空间后继续            try {                order_Queue.put(tempOrder);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName()+"--produce order--" + tempOrder);        }    }}

3、Redis List(Redis也支持发布订阅模式,同样可以实现生产者和消费者)

public class TestRedis {    private static final String REDIS_ADDR = "127.0.0.1:6379:0";    private static final String REDIS_LIST_KEY = "myList";    private static final int MAX_COUNT = 200;    public static void main(String[] args) {        RedisListDao_C redisListDao = new RedisListDao_C(REDIS_ADDR);        Thread consumerT = new Thread(new ConsumerThread(redisListDao, REDIS_LIST_KEY));        Thread producerT = new Thread(new ProducerThread(redisListDao, REDIS_LIST_KEY,MAX_COUNT));        producerT.start();        consumerT.start();    }}class ConsumerThread implements Runnable {    RedisListDao_C redisDao;    String redisListKey;    public ConsumerThread(RedisListDao_C redisListDao,String redisListKey){        this.redisDao = redisListDao;        this.redisListKey = redisListKey;    }    public void run() {        while(true){            // 使用blpop,当没有订单可消费时,进入阻塞状态,超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely)             // blpop传入参数示例:key1 key2 key3 timeout            // blpop返回第一个不为空的列表记录,示例:key1 value1            List<String> value = redisDao.blpop(new String[]{redisListKey,"0"});            if(value == null)                continue;            System.out.println(Thread.currentThread().getName() + "--consume--" + value.get(1));        }    }}class ProducerThread implements Runnable {    RedisListDao_C redisDao;    String redisListKey;    int MAX_COUNT;    Random random = new Random();    public ProducerThread(RedisListDao_C redisListDao,String redisListKey,int maxCount){        this.redisDao = redisListDao;        this.redisListKey = redisListKey;        MAX_COUNT = maxCount;    }    public void run() {        while(true){            String tempValue = "Order"+random.nextInt(1000);            redisDao.rpush(redisListKey,tempValue);            System.out.println(Thread.currentThread().getName() + "--Produce--" + tempValue);            // 达到阈值后暂停10秒钟再生产,注意:虽然一直在生产,很容易达到200阈值,但是也一直在消费(清除)            if(redisDao.len(redisListKey) >= MAX_COUNT){                try {                    Thread.sleep(10000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}

4、MessageQueue