英文:
Java ArrayBlockingQueue blocking until the queue has something in it
问题
以下是您要求的翻译内容:
我有许多不同的套接字连接到我的代码,每个套接字都在独立的线程上监听。在任何这些套接字接收到对象之前,时间可能会过去。因此,我有一个持续运行的 while(running) 循环。
为了同步所有不同的线程,我使用了一个 ArrayBlockingQueue。每当套接字/线程组合接收到一个对象时,我会将该对象添加到 ArrayBlockingQueue 中(因为它会自动为我同步)。然后在 while(running) 循环中,我会取出对象并处理它。
问题是在 while(running) 循环中,处理器会变得非常忙碌... 理想情况下,我希望在开始处理所有对象之前能够阻塞,直到 ArrayBlockingQueue 实际上有要处理的内容,以希望处理器不会继续运行。
您知道这是否可能?
以下是导致处理器旋转并浪费周期的我当前的代码...
@Override
public void run()
{
while(running)
{
while(messageQueue.size() > 0)
{
Object o = messageQueue.remove();
}
}
}
以下是我希望的...
@Override
public void run()
{
while(running)
{
messageQueue.BlockUntilSomethingInHere();
while(messageQueue.size() > 0)
{
Object o = messageQueue.remove();
}
}
}
英文:
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.
Then to synchronize all the different threads, I have an ArrayBlockingQueue. Whenever a socket/thread combo receives an object, I then add that object to the ArrayBlockingQueue (since it is automatically synchronized for me). Then in the while(running) code, I remove the object and process it.
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.
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();
}
}
}
答案1
得分: 2
请注意,在执行messageQueue.remove()
之前检查messageQueue.size() > 0
被称为检查然后操作反模式。如果有多个线程在移除元素,则在检查和随后的操作之间可能会导致条件发生更改,从而引发异常。
只需使用take()
替代remove()
:
while(running) try {
Object o = messageQueue.take();
// ...
} catch(InterruptedException ex) {
// 下一次循环迭代之前将会检查(running)
}
take()
将等待直到有元素可用。要在队列为空时结束此循环,必须将running
设置为false
并中断线程。如果无法中断线程,可以使用定时等待:
while(running) try {
Object o = messageQueue.poll(1, TimeUnit.SECONDS);
if(o != null) {
// ...
}
}
catch(InterruptedException ex) {
// 下一次循环迭代之前将会检查(running)
}
然后,线程在等待空队列时对设置为false
的running
做出反应最多可能需要一秒钟(请确保将running
声明为volatile
)。可以更改超时时间,以在响应性和CPU消耗之间进行权衡。
英文:
Note that checking for messageQueue.size() > 0
before performing messageQueue.remove()
is known as the check-then-act antipattern. 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()
:
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. To end this loop when the queue is empty, you have to set running
to false
and interrupt the thread. 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
). The timeout can be changed, to trade off responsiveness and CPU consumption.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论