原文链接:http://www.cnblogs.com/happyPawpaw/archive/2013/01/18/2865957.html

java实现生产者消费者问题 

引言

  生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况:

生产者消费者图

  存储空间已满,而生产者占用着它,消费者等着生产者让出空间从而去除产品,生产者等着消费者消费产品,从而向空间中添加产品。互相等待,从而发生死锁。

JAVA解决线程模型的三种方式

  1、wait()和notify()

复制代码
import java.util.LinkedList;

public class ProducerConsumer {
    private LinkedList<Object> storeHouse = new LinkedList<Object>();
    private int MAX = 10;

    public ProducerConsumer() {
    }

    public void start() {
        new Producer().start();
        new Comsumer().start();
    }

    class Producer extends Thread {
        public void run() {
            while (true) {
                synchronized (storeHouse) {
                    try {
                        while (storeHouse.size() == MAX) {
                            System.out.println("storeHouse is full , please wait");
                            storeHouse.wait();
                        }
                        Object newOb = new Object();
                        if (storeHouse.add(newOb)) {
                            System.out.println("Producer put a Object to storeHouse");
                            Thread.sleep((long) (Math.random() * 3000));
                            storeHouse.notify();
                        }
                    } catch (InterruptedException ie) {
                        System.out.println("producer is interrupted!");
                    }

                }
            }
        }
    }

    class Comsumer extends Thread {
        public void run() {
            while (true) {
                synchronized (storeHouse) {
                    try {
                        while (storeHouse.size() == 0) {
                            System.out.println("storeHouse is empty , please wait");
                            storeHouse.wait();
                        }
                        storeHouse.removeLast();
                        System.out.println("Comsumer get  a Object from storeHouse");
                        Thread.sleep((long) (Math.random() * 3000));
                        storeHouse.notify();
                    } catch (InterruptedException ie) {
                        System.out.println("Consumer is interrupted");
                    }

                }
            }

        }
    }

    public static void main(String[] args) throws Exception {
        ProducerConsumer pc = new ProducerConsumer();
        pc.start();
    }
}
复制代码

 

  2、await()和signal(),即线程锁的方式

复制代码
package sort;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumer {
    private LinkedList<Object> myList = new LinkedList<Object>();
    private int MAX = 10;
    private final Lock lock = new ReentrantLock();
    private final Condition full = lock.newCondition();
    private final Condition empty = lock.newCondition();

    public ProducerConsumer() {
    }

    public void start() {
        new Producer().start();
        new Consumer().start();
    }

    public static void main(String[] args) throws Exception {
        ProducerConsumer s2 = new ProducerConsumer();
        s2.start();
    }

    class Producer extends Thread {
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (myList.size() == MAX) {
                        System.out.println("warning: it's full!");
                        full.await();
                    }
                    Object o = new Object();
                    if (myList.add(o)) {
                        System.out.println("Producer: " + o);
                        empty.signal();
                    }
                } catch (InterruptedException ie) {
                    System.out.println("producer is interrupted!");
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    class Consumer extends Thread {
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (myList.size() == 0) {
                        System.out.println("warning: it's empty!");
                        empty.await();
                    }
                    Object o = myList.removeLast();
                    System.out.println("Consumer: " + o);
                    full.signal();
                } catch (InterruptedException ie) {
                    System.out.println("consumer is interrupted!");
                } finally {
                    lock.unlock();
                }
            }
        }
    }

}
复制代码

 

  3、阻塞队列的方式

复制代码
import java.util.concurrent.*;

public class ProducerConsumer {
    // 建立一个阻塞队列
    private LinkedBlockingQueue<Object> queue = new LinkedBlockingQueue<Object>(10);

    public ProducerConsumer() {
    }

    public void start() {
        new Producer().start();
        new Consumer().start();
    }

    public static void main(String[] args) throws Exception {
        ProducerConsumer s3 = new ProducerConsumer();
        s3.start();
    }

    class Producer extends Thread {
        public void run() {
            while (true) {
                try {
                    Object o = new Object();
                    // 取出一个对象
                    queue.put(o);
                    System.out.println("Producer: " + o);
                } catch (InterruptedException e) {
                    System.out.println("producer is interrupted!");
                }
                // }
            }
        }
    }

    class Consumer extends Thread {
        public void run() {
            while (true) {
                try {
                    // 取出一个对象
                    Object o = queue.take();
                    System.out.println("Consumer: " + o);
                } catch (InterruptedException e) {
                    System.out.println("producer is interrupted!");
                }
                // }
            }
        }
    }

}
复制代码

结论

  三种方式原理一致,都是对独占空间加锁,阻塞和唤醒线程,第一种方式比较传统,第三种方式最简单,只需存储和取用,线程同步的操作交由LinkedBlockingQueue全权处理。

=======================================================================================================================================

使用lock/condition实现生产者消费者模式如下:

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


class Buffer {
    private  final Lock lock;
    private  final Condition notFull;
    private  final Condition notEmpty;
    private int maxSize;
    private List<Date> storage;
    Buffer(int size){
        //使用锁lock,并且创建两个condition,相当于两个阻塞队列
        lock=new ReentrantLock();
        notFull=lock.newCondition();
        notEmpty=lock.newCondition();
        maxSize=size;
        storage=new LinkedList<>();
    }
    public void put()  {
        lock.lock();
        try {   
            while (storage.size() ==maxSize ){//如果队列满了
                System.out.print(Thread.currentThread().getName()+": wait \n");;
                notFull.await();//阻塞生产线程
            }
            storage.add(new Date());
            System.out.print(Thread.currentThread().getName()+": put:"+storage.size()+ "\n");
            Thread.sleep(1000);         
            notEmpty.signalAll();//唤醒消费线程
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{   
            lock.unlock();
        }
    }

    public  void take() {       
        lock.lock();
        try {  
            while (storage.size() ==0 ){//如果队列满了
                System.out.print(Thread.currentThread().getName()+": wait \n");;
                notEmpty.await();//阻塞消费线程
            }
            Date d=((LinkedList<Date>)storage).poll();
            System.out.print(Thread.currentThread().getName()+": take:"+storage.size()+ "\n");
            Thread.sleep(1000);         
            notFull.signalAll();//唤醒生产线程

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    } 
}

class Producer implements Runnable{
    private Buffer buffer;
    Producer(Buffer b){
        buffer=b;
    }
    @Override
    public void run() {
        while(true){
            buffer.put();
        }
    }   
}
class Consumer implements Runnable{
    private Buffer buffer;
    Consumer(Buffer b){
        buffer=b;
    }
    @Override
    public void run() {
        while(true){
            buffer.take();
        }
    }   
}
public class Main{
    public static void main(String[] arg){
        Buffer buffer=new Buffer(10);
        Producer producer=new Producer(buffer);
        Consumer consumer=new Consumer(buffer);
        for(int i=0;i<3;i++){
            new Thread(producer,"producer-"+i).start();
        }
        for(int i=0;i<3;i++){
            new Thread(consumer,"consumer-"+i).start();
        }
    }
}

 

posted on 2017-09-07 10:50  blythe  阅读(109)  评论(0编辑  收藏  举报