使用Executor Framework实现生产者 - 消费者模式

时间:2011-11-09 22:09:45

标签: java multithreading

我有两个主题,一个消费者和一个制作人。消费者线程是主线程,而生产者线程是由我使用的第三方库创建的。

您使用List的{​​{1}}向生产者线程请求ProducerChannel数据,该requestData()会立即返回。然后,生产者线程将异步生成数据,并使用回调方法发送每个数据。我想要请求数据的方法同步返回结果。最直接的方法是使用wait()notify(),如下所示。

public class DataFeed {
    boolean done;
    private List<Data> dataList;
    private ProducerChannel producerChannel;

    // This method should be synchronous.
    public List<Data> getDataList() {
        this.producerChannel.requestData();

        while (!done) {
            wait();
        }

        List<Data> dataList = this.dataList;
        this.dataList = null;

        return dataList;
    }

    // This is the call back method invoked by the producer thread.  
    public void generated(Data data) {
        if (data == null) {
            done = true; // End of data.
            notify();
        }
        else {
            this.dataList.add(data);
        }
    }
}

请注意,整个应用程序中只有一个消费者线程。这就是DataFeed只有一个List来保存每个请求的结果的原因。我了解到Executor框架现在是管理线程的首选方式。如何重构此类,以便在不创建其他线程时不显式使用Thread个对象?

5 个答案:

答案 0 :(得分:2)

我认为你应该看一下BlockingQueue javadoc上的生产者 - 消费者例子:

http://download.oracle.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html

答案 1 :(得分:1)

我真的不关注你。此类不会创建任何线程。因此,使用执行程序框架不会让你在这里。

使用wait和notify,使用显式同步和线程通信,您可以使用BlockingQueue。生产者在数据准备好时将列表添加到阻塞队列,并且在阻塞队列为空时消耗器阻塞。

答案 2 :(得分:1)

如果您不关心生成的集合的大小或按索引获取项目,那么BlockingQueue可能就是您所需要的。如果你关心那些事情(即你实际上需要一个java.util.List而不是Collection,或者如果由于某种原因你不能使用延迟集合那么你仍然可以使用{{1 }和wait()

您需要将他们的synchronized关键字添加到您的getDataList和生成的方法中,否则您将获得notify()

像这样:IllegalStateMonitorException

但如果这是您想要去的路线,请谨慎使用。任意数量的线程都可以同时调用public synchronized List<Data> getDataList() throws InterruptedException{。即使它已同步,您也可以通过调用getDataList()

来释放监视器锁定

就个人而言,我会选择BlockingQueue

答案 3 :(得分:0)

Here is the example关于如何使用阻止队列来解决生产者消费者问题

答案 4 :(得分:0)

我是OP。虽然BlockingQueue肯定会奏效,但我了解到Semaphore将是一个更简单的解决方案。