关于我实施Producer Consumer的建议

时间:2013-11-05 01:24:10

标签: java multithreading

我在多线程中很天真,并且正在尝试学习它的概念。这是我对Producer-Consumer问题的实现。如果它不正确/粗糙/任何其他可以改善我的设计的建议,请查看并建议我。

static int data = 0;
static Object obj1 = new Object();

static class Producer implements Runnable {

    public void run() {
        produce();
    }

    void produce() {
        while (true) {

                if (data < 5){
                    synchronized(obj1){
                    System.out.println("Producing Data. Now Data is "+data++);
                    obj1.notifyAll();
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                else{
                    try {
                        System.out.println("Producer inactive");
                        synchronized(obj1){
                        obj1.wait();
                        }
                        System.out.println("Producer active");
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

        }
    }
}

    static class Consumer implements Runnable{

        public void run(){
            consume();
        }
        void consume() {
            while (true) {

                    if (data > 0){
                        synchronized(obj1){
                        System.out.println("Consuming Data. Now Data is "+data--);
                        obj1.notifyAll();
                        }
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    else{
                        try {
                            System.out.println("Consumer Inactive");
                            synchronized(obj1){
                            obj1.wait();
                            }
                            System.out.println("Consumer Active");

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

            }
        }
    }

2 个答案:

答案 0 :(得分:1)

好几点。生产者和消费者通常共享数据结构。静态数据的使用非常奇怪,坦率地说没有意义。通常,您要共享的是数据结构,如生产者和消费者之间的队列。生产者将把东西添加到队列的尾部,消费者将从队列的头部(FIFO - 先出先出)中抽取东西。现在我没有看到这一点,那么究竟是什么产生消费?

良好的生产者消费者体系结构并不太关心交换什么类型的数据,因此您可以在其上传递许多不同类型的数据。这就是面向对象命令架构将帮助您的地方。在此示例中,SomeMessage表示某个对象层次结构的根,因此可以交换各种消息。

以下是如何在程序中实例化Producer-Consumer架构的简单示例:

public class SomeClient {
   public void start() {
       Queue sharedQueue = new LinkedList();

       producer = new Producer( sharedQueue );
       consumer = new Consumer( sharedQueue );

       producer.start();
       consumer.start();
   }
}

以下是其实施:

public class Producer implements Runnable {
    Thread thread;
    Queue queue;

    public Producer(Queue queue) {
       this.queue = queue;
    }

    public void start() {
       thread = new Thread(this);
       thread.start();
    }

    public void shutdown() {
       thread.interrupt(); // request a shutdown
       thread.join();      // make sure we wait until Producer.thread exits before this thread continues
    }

    public void run() {
        try {
           while( !Thread.isInterrupted() ) {
               SomeMessage message = produceAMessage();
               synchronized( queue ) {
                  queue.add( message );
                  queue.notifyAll();
               }
           }
        } catch( InterruptedException ex ) {
           System.out.println("Producer shutting down per request.");
        } finally {
           thread = null;
        }
    }
}

public class Consumer implements Runnable {
    Thread thread;
    Queue queue;

    public Consumer( Queue queue ) {
        this.queue = queue;
    }

    public void start() {
        thread = new Thread( this );
        thread.start();
    }

    public void shutdown() {
       thread.interrupt(); // request a shutdown
       thread.join();      // make sure we wait until Consumer.thread exits before this thread continues
    }

    public void run() {
        try {
           while( !thread.isInterrupted() ) {
               SomeMessage message = take();
               doSomethingWithMessage( message );
           }
        } catch( InterruptedException ex ) {
           System.out.println("Stop processing - consumer per request.");
        } finally {
           thread = null;
        }
    }

    private SomeMessage take() throws InterruptedException {
       synchronized( queue ) {
           queue.wait();
           return queue.remove();
       }
    }
}

这个实现中有两点不同。 Producer和Consumer共享一个Queue实例,他们使用该实例执行同步调用。这样就不会在没有拥有锁的情况下从该结构写入或读取。在他们添加到队列(生产者)或从队列(消费者)中删除后,他们不需要使用同步。它们可以自由处理而无需相互通信。他们通过添加尾部和从头部绘制来在每个实例之间交换SomeMessage的实例。

take()方法在此代码中非常重要。如果没有辅助方法,则无法处理消息并释放锁定。这一点非常重要,以便您的消费者可以接收消息并放开锁定以允许其他生产者/消费者在此特定消费者处理消息时添加/删除消息。这样可以尽可能快地保持吞吐量。

是的,我说生产者。这种架构允许多个生产者和多个消费者,而无需更改生产者或消费者的内部。

请注意,捕获InterruptedException不在while循环中。如果您想要一个可以完全关闭的可预测程序,这一点非常重要。 InterruptedException和中断的概念是表现良好的Java线程的核心。如果您不知道在什么条件下生成此异常,您将永远不会理解Java中的多线程应用程序。这不是随机发生的。无法以编程方式停止Java线程。另一个线程必须请求它自己中断。并且线程必须遵守请求,否则它将不会停止。所以,如果我们得到一个。关掉。在这个程序中,我们只会在调用wait或notify时获取它,这意味着在我们处理消息时我们不会被中断。消费者将在停止前完成消息处理。

最后,考虑到Java中的并发库,实现Producer-Consumer关系实际上要容易得多,但这是一个很好的例子,说明如何在最低级别的Java上实现它以了解这些库正在为您做什么。

答案 1 :(得分:0)

封装消费和生产行为可以更加可重用。在下面的代码中,我将消费者/生产者线程中的共享资源同步问题解耦,这可能有助于解决像对象池和连接池等类似问题。

import java.util.LinkedList;
import java.util.Queue;

public class ProducerConsumer {

    public static void main(String[] args) {
        SyncQueue syncQueue = new SyncQueue(1);
        Producer producer = new Producer(syncQueue , 10);
        Consumer consumer = new Consumer(syncQueue,10);

        producer.start();
        consumer.start();
    }

}

class SyncQueue {
    private Queue<Integer> queue = new LinkedList<Integer>();
    private Integer size;
    public SyncQueue(Integer size) {
        super();
        this.size = size;
        this.signalledBefore = false;
    }

    public synchronized void put(Integer data){
        while(queue.size() == size){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        queue.add(data);
        notifyAll();
    }
    public synchronized Integer get(){
        while(queue.isEmpty()){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Integer data = queue.remove();
        notifyAll();
        return data;
    }
}

class Producer extends Thread{

    private SyncQueue syncQueue;
    private Integer size;
    public Producer(SyncQueue syncQueue, Integer size) {
        this.syncQueue = syncQueue;
        this.size = size;
    }
    @Override
    public void run() {
        for (Integer i = 0; i < size; i++) {
            syncQueue.put(i);
            System.out.println("Produced:" + i);
            try {
                sleep((int)Math.random()*100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

}

class Consumer extends Thread{

    private SyncQueue syncQueue;
    private Integer size;

    public Consumer(SyncQueue syncQueue, Integer size) {
        this.syncQueue = syncQueue;
        this.size = size;
    }

    @Override
    public void run() {
        for (Integer i = 0; i < size; i++) {
            try {
                sleep((int)Math.random()*100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Consumed:" + syncQueue.get());
        }
    }
}
相关问题