从Java BlockingQueue获取之前检查

时间:2013-02-26 04:01:31

标签: java concurrency

我遇到的问题就像单个生产者多个消费者问题。除了消费者是“不同的”,我需要一种“偷看”新项目(以检查它的用途)的方式。

问题实际上是一个服务于多个客户端线程的服务器线程。客户端将请求信息,然后服务器应回复此客户端

我该怎么做?可能性是一个循环:

while (true) {
    if (q.peek() ... check here ...) {
        // do something
    } else {
        Sleep(...); // prevent taking up too much CPU?
    }
}

但似乎并不理想/对吗?

3 个答案:

答案 0 :(得分:2)

以下是两个选项:

选项1.让队列中的一个消费者关闭项目并将其委托给“真正的”消费者。这个需要你做很多工作,因为你的主要消费者必须知道哪些“真正的”消费者忙碌。此外,如果其中一个“真实”消费者获得的资源多于其他消费者,则当主消费者等待传递消息时,它有可能阻止队列。

更好的解决方案是:

选项2.为每种类型的消费者使用一个队列。您的生产者将确定每种消息类型所属的队列,并将其放入正确的队列中。然后每个消费者都会从它感兴趣的队列中拉出来。

答案 1 :(得分:0)

您可能需要通过在单个块中同步它们来使以下操作成为原子。

// Make sure queue is final. If not, use a final Object monitor.
synchronized(queue) {
    queue.peek
    queue.pool
}

这是为了确保在您的消费者线程发现队列包含正确的目标消息(通过BlockingQueue.peek)后,它可以使用该消息(通过BlockingQueue.pool

但是,您的解决方案并不理想。您正在实现名为busy pooling的技术,这会浪费大量CPU资源。你没有利用BlockingQueue.poolBlockingQueue.pool将使您的消费者线程处于等待阶段,直到数据可用。

为了充分利用BlockingQueue.pool,每个消费者线程都应该拥有自己的队列。这样他们就可以拨打pool而无需执行忙peek

答案 2 :(得分:0)

也许最好不要使用BlockingQueue:

public class Synchronizer {
    Object obj;

    synchronized void put(Object obj) throws InterruptedException {
        this.obj = obj;
        notifyAll();
        while(obj != null) {
            wait();
        }
    }

    synchronized Object take() throws InterruptedException {
        for(;;) {
            wait();
            if (obj instanceof MyObject) {
                notifyAll();
                Object tmp = obj;
                obj = null;
                return tmp;
            }
        }
    }
}

虽然可能有一个版本的Synchronzer消耗了BlockingQueue