简体   繁体   English

Java ArrayBlockingQueue 阻塞直到队列中有东西

[英]Java ArrayBlockingQueue blocking until the queue has something in it

I have a number of different sockets connecting to my code that are all each listening on independent threads.我有许多不同的套接字连接到我的代码,每个套接字都在独立线程上侦听。 Time may go by before an object is passed to any of these sockets.在将对象传递到这些套接字中的任何一个之前,时间可能会过去。 So I have a while(running) loop that runs basically forever.所以我有一个基本上永远运行的 while(running) 循环。

Then to synchronize all the different threads, I have an ArrayBlockingQueue.然后为了同步所有不同的线程,我有一个 ArrayBlockingQueue。 Whenever a socket/thread combo receives an object, I then add that object to the ArrayBlockingQueue (since it is automatically synchronized for me).每当套接字/线程组合接收到一个对象时,我就会将该对象添加到 ArrayBlockingQueue(因为它会自动为我同步)。 Then in the while(running) code, I remove the object and process it.然后在 while(running) 代码中,我删除对象并处理它。

The problem is that the processor goes crazy in that while(running) loop... Ideally I would like to block on starting to process all the objects until the ArrayBlockingQueue actually has something to process in hopes that the processor doesn't keep running.问题是处理器在那个 while(running) 循环中变得疯狂......理想情况下,我想阻止开始处理所有对象,直到 ArrayBlockingQueue 实际上有一些东西要处理,希望处理器不会继续运行。

Do you know if this is possible?你知道这是否可能?

Here is my current code that causes the processor to spin up and waste cycles...这是我当前的代码,它导致处理器旋转并浪费周期......

@Override
    public void run()
    {
        while(running)
        {
            while(messageQueue.size() > 0)
            {
                Object o = messageQueue.remove();
            }
        }
    }

Here is what I would like...这是我想要的...

@Override
    public void run()
    {
        while(running)
        {
            messageQueue.BlockUntilSomethingInHere();

            while(messageQueue.size() > 0)
            {
                Object o = messageQueue.remove();
            }
        }
    }

Note that checking for messageQueue.size() > 0 before performing messageQueue.remove() is known as the check-then-act antipattern.请注意,在执行messageQueue.remove()之前检查messageQueue.size() > 0被称为check-then-act反模式。 If you have more than one thread removing elements, there's the possibility that the condition changes between the check and the subsequent action, leading to an exception.如果您有多个线程移除元素,则有可能条件在检查和后续操作之间发生变化,从而导致异常。

Just use take() instead of remove() :只需使用take()而不是remove()

while(running) try {
    Object o = messageQueue.take();
    // ...
} catch(InterruptedException ex) {
    // (running) will be checked before the next loop iteration
}

take() will wait until an element becomes available. take()将等待元素变为可用。 To end this loop when the queue is empty, you have to set running to false and interrupt the thread.要在队列为空时结束此循环,您必须将running设置为false并中断线程。 If interruption is not possible, you can use timed wait:如果无法中断,您可以使用定时等待:

while(running) try {
    Object o = messageQueue.poll​(1, TimeUnit.SECOND);
    if(o != null) {
        // ...
    }
}
catch(InterruptedException ex) {
  // (running) will be checked before the next loop iteration
}

Then, it may take up to a second until the thread waiting on an empty queue will react on running set to false (mind to declare running as volatile ).然后,可能需要一秒钟,直到等待空队列的线程对running设置为false做出反应(请注意将running声明为volatile )。 The timeout can be changed, to trade off responsiveness and CPU consumption.可以更改超时时间,以权衡响应能力和 CPU 消耗。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM