1

I am working on a system where I need a while(true) where the loop constantly listens to a queue and increments counts in memory.

The data is constantly coming in the queue, so I cannot avoid a while(true) condition. But naturally it increases my CPU utilization to 100%.

So, how can I keep a thread alive which listens to the tail of queue and performs some action, but at the same time reduce the CPU utilization to 100%?

zengr
  • 38,346
  • 37
  • 130
  • 192

6 Answers6

11

Blocking queues were invented exactly for this purpose.

Also see this: What are the advantages of Blocking Queue in Java?

Community
  • 1
  • 1
lbalazscs
  • 17,474
  • 7
  • 42
  • 50
  • But how can I use BlockingQueue here? I have a persistent queue implementation built over hsqldb. I receive() messages off the persistent queue. So, my while loop keeps polling the queue. – zengr Feb 08 '13 at 00:07
  • 2
    @zengr: We'd have to see your code. The idea is to *wait* for something to happen, not to constantly check if it has already happened. You just keep checking the queue over and over as fast as you can, which maxes out resources. – David Schwartz Feb 08 '13 at 00:11
  • 2
    If you're polling a database looking for changes (without knowing more about what you're doing - bad idea for a "queue") then you're going to have to `sleep()` and not continuously poll. – Brian Roach Feb 08 '13 at 00:12
  • @Brian Roach Well yeah, I agree. But hsqldb behaves a little differently. It has the data in memory and maintains log using which it reconstructs the data in case of a process restart. So, I am polling of a db yes, but the "selects" are in memory. Which is not that bad. – zengr Feb 08 '13 at 00:16
  • The problem is that you *constantly poll* but don't like that the constant poll constantly consumes resources. – Nik Bougalis Feb 08 '13 at 00:18
  • @zengr - I'm just talking about the non-blocking aspect of it. However, some quick googling finds http://hsqldb.org/doc/guide/triggers-chapt.html - I think you might want to look into triggers (specifically the part where you can create a class that gets notified), and implement your queue so it blocks if there's nothing in it, then unblocks on a trigger. A quick glance at that page sugests that is possible, A `CountDownLatch` will be your friend here. – Brian Roach Feb 08 '13 at 00:19
  • I agree with both David and Brian, a queue implementation can be blocking and persistent at the same time, but if you need to listen to database changes, then you don't really have a queue, but you still can use Thread.sleep between two reads. – lbalazscs Feb 08 '13 at 00:20
  • I agree you should avoid polling if you can. If you must poll for updates, you might also consider using a BlockingQueue with a separate thread that checks for updates, puts new items in the queue, and then sleeps for some amount of time. Depending on your use case that might result in a cleaner design, especially if you have multiple consumers of the queue. – Alex Feb 08 '13 at 01:13
  • 1
    @zengr: It's worse with the data in memory. If it had to access a database over the network, that would at least slow it down and reduce its resource consumption because it would be waiting for a response from the database at least some of time. Since it's all in memory, it's never waiting for anything, just burning resources at the maximum conceivable speed. – David Schwartz Feb 08 '13 at 07:34
2

LinkedBlockingQueue.take() is what you should be using. This waits for an entry to arrive on the queue, with no additional synchronization mechanism needed.

(There are one or two other blocking queues in Java, IIRC, but they have features that make them unsuitable in the general case. Don't know why such an important mechanism is buried so deeply in arcane classes.)

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
2

usually a queue has a way to retrieve an item from it and your thread will be descheduled (thus using 0% cpu) until something arrives in the queue...

2

Based on your comments on another answer, you want to have a queue that is based on changes in hsqldb

Some quick googling turns up:

http://hsqldb.org/doc/guide/triggers-chapt.html

It appears you can set it up so that changes cause a trigger to occur, which will notify a class you write implementing the org.hsqldb.Trigger interface. Have that class contain a reference to a LinkedBlockingDequeue from the Concurrent package in Java and have the trigger add the change to the queue.

You now have a blocking queue that your reading thread will block on until hsqldb fires a trigger (from an update by a writer) which will put something in the queue. The waiting thread will then unblock and have the item off the queue.

Brian Roach
  • 76,169
  • 12
  • 136
  • 161
  • +1 for DB trigger. I'm not familiar with that DB, but this is the best answer if it is supported. – Martin James Feb 08 '13 at 00:35
  • @Brian What do you think about this: http://stackoverflow.com/a/14764347/231917 ? – zengr Feb 08 '13 at 01:36
  • @zengr - Yep, that will work. In the case of no data being there you're only going to "waste" something in the sub-millisecond range in terms of CPU utilization more than likely. If your requirements allow for data to be 10 seconds old then that's absolutely fine. – Brian Roach Feb 08 '13 at 01:47
  • Yeah 10sec delay is accepted. Its a log collector which counts system health "ticks". – zengr Feb 08 '13 at 02:06
1

lbalazscs and Brain have excellent answers. I couldn’t share my code it was hard for them to give them the exact fix for my issue. And having a while(true) which constantly polls a queue is surely the wrong way to go about it. So, here is what I did:

  1. I used ScheduledExecutorService with a 10sec delay.
  2. I read a block of messages (say 10k) and process those messages
  3. thread is invoked again and the "loop" continues.

This considerably reduces my CPU usage. Suggestions welcomed.

zengr
  • 38,346
  • 37
  • 130
  • 192
-2

Lots of dumb answers from people who read books and only wasted time in schools, not as many direct logic or answers I see.

while(true) will set your program to use all the CPU power that's basically 'alloted' to it by the windows algorithms to run what is in the loop, usually as-fast-as-possible over and over. This doesn't mean if it says 100% on your application, that if you run a game, your empty loop .exe will be taking all your OS CPU power, the game should still run as intended. It is more like a visual bug, similar to the windows idle process and some other processes. The fix is to add a Sleep(1) (at least 1 millisecond) or better yet a Sleep(5) to make sure other stuff can run and ensure the CPU is not constantly looping your while(true) as fast as possible. This will generally drop CPU usage to 0% or 1% in the visual queue as 1 full millisecond is a big resting time for even older CPU.

Many times while(trues) or generic endless loops are bad designs and can be drastically slowed down to even Sleep(1000) - 1 second interval checks or higher. Endless loops are not always bad designs, but usually they can be improved..

funny to see this bug I learned whe nI was like 12 learning C pop up and all the 'dumb' answers given.

Just know if you try it, unless the scripted slower language you have learned to use has fixed it somewhere along the line by itself, windows will claim to use a lot of CPU on doing an empty loop when the OS is actually having free resources to spend.

Jurugi
  • 1
  • 1