A colleague of mine showed me a nice idiom with BlockingQueue
for performing a fixed amount of work:
final List<T> work = new ArrayList<T>(N); for (;;) { // Wait until there is some work work.add(queue.take()); // Get more work, if available queue.drainTo(work, N - 1); for (final T item : work) process(item); work.clear(); }
This idiom works on 1 to N chunks at a time efficiently and succinctly.
An example use is batching SQL updates. At the top of the loop begin the batch transaction after take()
and finish the batch after the processing loop.
UPDATE: This idiom is also more efficient when unbounded amounts of work:
queue.drainTo(work);
Every call to take()
is blocking and checks a lock — essentially giving up any remaining thread time slice. Using drainTo(work)
avoids this lost thread work, cutting down on lock checks.
3 comments:
Is it thread safe? Ff some other thread put item to queue in the same time, what is the behaviour?
BlockingQueue is an interfaced for a family of concurrent collections -- you cannot predict if the new item will make it into the work list or not, but nothing surprising happens.
take() is a blocking operation if nothing is there. It does require acquiring the lock, but unless someone else owns it then the thread won't block and won't "give up the rest of its timeslice".
Post a Comment