Java 生产者消费者问题

来源:互联网 发布:淘宝佣金是多少 编辑:程序博客网 时间:2024/05/01 15:07
在JAVA中,一共有四种方法支持同步,其中三个是同步方法,一个是管道方法。
1.       方法wait()/notify()
2.       方法await()/signal()
3.       阻塞队列方法BlockingQueue
4.       管道方法PipedInputStream/PipedOutputStream
下面我们看各个方法的实现:

1.       方法wait()/notify()

wait()和notify()是根类Object的两个方法,也就意味着所有的JAVA类都会具有这个两个方法,为什么会被这样设计呢?我们可以认为所有的对象默认都具有一个锁,虽然我们看不到,也没有办法直接操作,但它是存在的。
wait()方法表示:当缓冲区已满或空时,生产者或消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让另一个线程开始执行;
notify()方法表示:当生产者或消费者对缓冲区放入或取出一个产品时,向另一个线程发出可执行通知,同时放弃锁,使自己处于等待状态。
下面是一个例子代码:
package thread;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()

在JDK5.0以后,JAVA提供了新的更加健壮的线程处理机制,包括了同步、锁定、线程池等等,它们可以实现更小粒度上的控制。await()和signal()就是其中用来做同步的两种方法,它们的功能基本上和wait()/notify()相同,完全可以取代它们,但是它们和新引入的锁定机制Lock直接挂钩,具有更大的灵活性。
下面是一个例子代码:
package thread;import java.util.LinkedList;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ProducerConsumer2 {    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 ProducerConsumer2() {    }    public void start() {        new Producer().start();        new Consumer().start();    }    public static void main(String[] args) throws Exception {        ProducerConsumer2 s2 = new ProducerConsumer2();        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.       阻塞队列方法BlockingQueue

BlockingQueue也是JDK5.0的一部分,它是一个已经在内部实现了同步的队列,实现方式采用的是我们的第2种await()/signal()方法。它可以在生成对象时指定容量大小。
它用于阻塞操作的是put()和take()方法。
put()方法类似于我们上面的生产者线程,容量最大时,自动阻塞。
take()方法类似于我们上面的消费者线程,容量为0时,自动阻塞。
下面是一个例子代码:
package thread;import java.util.concurrent.*;public class ProducerConsumer3 {    // 建立一个阻塞队列    private LinkedBlockingQueue<Object> queue = new LinkedBlockingQueue<Object>(10);    public ProducerConsumer3() {    }    public void start() {        new Producer().start();        new Consumer().start();    }    public static void main(String[] args) throws Exception {        ProducerConsumer3 s3 = new ProducerConsumer3();        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!");                }            }        }    }}

4.       管道方法PipedInputStream/PipedOutputStream

这个类位于java.io包中,是解决同步问题的最简单的办法,一个线程将数据写入管道,另一个线程从管道读取数据,这样便构成了一种生产者/消费者的缓冲区编程模式。

package thread;import java.io.*;public class ProducerConsumer4{    private PipedOutputStream pos;    private PipedInputStream pis;    //private ObjectOutputStream oos;    //private ObjectInputStream ois;        public ProducerConsumer4(){        try{            pos = new PipedOutputStream();            pis = new PipedInputStream(pos);            //oos = new ObjectOutputStream(pos);            //ois = new ObjectInputStream(pis);        }catch(IOException e){            System.out.println(e);        }    }        public void start(){        new Producer().start();        new Consumer().start();    }        public static void main(String[] args) throws Exception{    ProducerConsumer4 s4 = new ProducerConsumer4();        s4.start();    }        class Producer extends Thread{        public void run(){            try{                while(true){                    int b = (int) (Math.random() * 255);                    System.out.println("Producer: a byte, the value is " + b);                    pos.write(b);                    pos.flush();                    //Object o = new MyObject();                    //oos.writeObject(o);                    //oos.flush();                    //System.out.println("Producer: " + o);                }            }catch(Exception e){                //System.out.println(e);                e.printStackTrace();            }finally{                try{                    pos.close();                    pis.close();                    //oos.close();                    //ois.close();                }catch(IOException e){                    System.out.println(e);                }            }        }    }        class Consumer extends Thread{        public void run(){            try{                while(true){                    int b = pis.read();                    System.out.println("Consumer: a byte, the value is " + String.valueOf(b));                    //Object o = ois.readObject();                    //if(o != null)                        //System.out.println("Consumer: " + o);                }            }catch(Exception e){                //System.out.println(e);                e.printStackTrace();            }finally{                try{                    pos.close();                    pis.close();                    //oos.close();                    //ois.close();                }catch(IOException e){                    System.out.println(e);                }            }        }    }        //class MyObject implements Serializable {    //}}

0 0