0

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();
            }
        }
    }
2
  • 3
    while(messageQueue.size() > 0): Just remove that. Commented Oct 19, 2020 at 1:58
  • 2
    @MarquisofLorne mind that remove() is nonblocking. It has to be replaced by a blocking method to get rid of the pretest. Commented Oct 19, 2020 at 14:22

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.