views:

1289

answers:

5

Hello Everybody,

I have the classic problem of a thread pushing events to the incoming queue of a second thread. Only this time, I am very interested about performance. What I want to achieve is:

  • I want concurrent access to the queue, the producer pushing, the receiver poping.
  • When the queue is empty, I wand the consumer to block to the queue, waiting for the producer.

My first idea was to use a LinkedBlockingQueue, but I soon realized that it is not concurrent and the performance suffered. On the other hand, I now use a ConcurrentLinkedQueue, but still I am paying the cost of wait()/notify() on each publication. Since the consumer, upon finding an empty queue, does not block, I have to synchronize and wait() on a lock. On the other part, the producer has to get that lock and notify() upon every single publication. The overall result is that I am paying the cost of sycnhronized (lock) {lock.notify()} in every single publication, even when not needed.

What I guess is needed here, is a queue that is both blocking and concurrent. I imagine a push() operation to work as in ConcurrentLinkedQueue, with an extra notify() to the object when the pushed element is the first in the list. Such a check I consider to already exist in the ConcurrentLinkedQueue, as pushing requires connecting with the next element. Thus, this would be much faster than synchronizing every time on the external lock.

Is something like this available/reasonable?

+2  A: 

Here is a list of classes implementing BlockingQueue.

I would recommend checking out SynchronousQueue.

Like @Rorick mentioned in his comment, I believe all of those implementations are concurrent. I think your concerns with LinkedBlockingQueue may be out of place.

jjnguy
SynchronousQueue is not what I want, as it will block my producer each time that it is trying to publish .
Papajohn
SynchronousQueue looks more like a pipe, than queue. Looks like it cannot contain tasks pending processing in it, only "push" single tasks from producer to consumer.
Rorick
Hehe, sorry .
jjnguy
+2  A: 

I think you can stick to java.util.concurrent.LinkedBlockingQueue regardless of your doubts. It is concurrent. Though, I have no idea about its performance. Probably, other implementation of BlockingQueue will suit you better. There's not too much of them, so make performance tests and measure.

Rorick
I say this only by observing my throughput reducing roughly 8 times compared to ConcurrentLinkedQueue. I guessed it was locking the whole thing internally just to offer thread safety. You are right though, it might as well be just worse performance compared to ConcurrentLinkedQueue. Which kind of beats the cause ;-)
Papajohn
Which ever queue you use, you are going to end up using a lock to support the waiting for a new entry. (unless you busy wait) The lock really isn't that expensive (about 0.5 micro-seconds for Lock) so if its a performance problem you may have a problem with your design, e.g. create less tasks/find a way to add less objects to the queue/batch up your work.
Peter Lawrey
+2  A: 

I would suggest you look at ThreadPoolExecutor newSingleThreadExecutor. It will handle keeping your tasks ordered for you, and if you submit Callables to your executor, you will be able to get the blocking behavior you are looking for as well.

hasalottajava
A: 

I use the ArrayBlockingQueue whenever I need to pass data from one thread to another. Using the put and take methods (which will block if full/empty).

Javamann
+1  A: 

You can try LinkedTransferQueue from jsr166: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166y/

It fulfills your requirements and have less overhead for offer/poll operations. As I can see from the code, when the queue is not empty, it uses atomic operations for polling elements. And when the queue is empty, it spins for some time and park the thread if unsuccessful. I think it can help in your case.

Vitaly