views:

487

answers:

2

BlockingQueue has the method called drainTo() method but it is not blocked. I need a blocking queue that I want to blocked but also able to retrieve queued-object in a single method.

Object first = blockingQueue.take();

if ( blockingQueue.size() > 0 )
    blockingQueue.drainTo( list );

I guess the above code will work but I'm looking for an elegant solution.

+2  A: 

Are you referring to the comment in the JavaDoc:

Further, the behavior of this operation is undefined if the specified collection is modified while the operation is in progress.

I believe that this refers to the collection list in your example:

blockingQueue.drainTo(list);

meaning that you cannot modify list at the same time you are draining from blockingQueue into list. However, the blocking queue internally synchronizes so that when drainTo is called, puts and gets will block. If it did not do this, then it would not be truly Thread-safe. You can look at the source code and verify that drainTo is Thread-safe regarding the blocking queue itself.

Alternately, do you mean that when you call drainTo that you want it to block until at least one object has been added to the queue? In that case, you have little choice other than:

list.add(blockingQueue.take());
blockingQueue.drainTo(list);

to block until one or more items have been added, and then drain the entire queue into the collection list.

Eddie
It's unlikely that the collection you are copying to would be thread-safe. What would be the point?
Tom Hawtin - tackline
Is it guaranteed that drainTo(list) won't call list.clear()? I don't see that in the javadoc anywhere.
Recurse
@Recurse: The JavaDoc doesn't *guarantee* that drainTo(list) won't call clear(), I suppose, because it doesn't say it won't do so. However, it would be very surprising if it did something so major to a collection passed to it without documenting this action. Many would consider this to be a serious bug.
Eddie
A: 

With the API available, I don't think you are going to get much more elegant. Other than you can remove the size test.

If you are wanting to atomically retrieve a contiguous sequence of elements even if another removal operation coincides, I don't believe even drainTo guarantees that.

Tom Hawtin - tackline
drainTo definitely blocks any put, get, take, etc... Check the source code. This API is thread-safe against other calls to the blocking queue. However, if the Collection to which you are draining changes during drainTo, you can have a problem.
Eddie
Check the source code? It's an interface!
Tom Hawtin - tackline
OK, true, funny, but besides the point. Check the implementing classes in the JDK. (Which is clearly what I meant.)
Eddie
They are not the only possible implementation classes. For instance, I'm sure it is relatively straightforward(!) to convert ConcurrentLinkedQueue to a "ConcurrentLinkedBlockingQueue" (although clearly the blocking operations would not be wait-free).
Tom Hawtin - tackline