Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #33121
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Newsgroups | comp.lang.java.programmer |
| Subject | To BlockingQueue or not to BlockingQueue? |
| Date | 2015-11-13 09:13 -0500 |
| Organization | A noiseless patient Spider |
| Message-ID | <n24r35$f4s$1@dont-email.me> (permalink) |
Short version: I wrote a simple submit-tasks-and-reap-results
class based on a ThreadPoolExecutor. Initially it seemed I could
use an ExecutorCompletionService to manage the flow of work, but
that didn't pan out. Then I tried having the tasks place their own
results on a BlockingQueue explicitly, but that didn't pan out either.
Eventually, I retrogressed all the way to using an ordinary Queue and
an old-fashioned synchronized/wait/notifyAll scheme. I'm hoping for
some hints about how to use the java.util.concurrent classes better,
since they're more modern and fashionable.
Longer version: What I wanted was a multi-threaded server class
to which clients could submit tasks and from which they could retrieve
results as they became available. The submissions and retrievals might
happen in one client thread or in many, but they'd all be the same
"kind" of job (thus, no need to deliver a result to the same client
thread that submitted the task; any client could accept any result).
That much is pretty simple, and an ExecutorCompletionService looks like
a perfect match -- but there were a few wrinkles:
1) If the worker threads get too far ahead of the consuming clients
and start clogging the system with too many unretrieved results, I want
the workers to pause until the backlog diminishes.
2) If a client tries to retrieve a result and none is ready yet,
the client should wait. But if there are no tasks in the system, no
results are forthcoming and the client should be sent away empty-handed
(I used NoSuchElementException, but a null return would also work).
3) There should be a way to shut the whole thing down, either
gracefully (finish all submitted tasks first) or forcibly (discard all
tasks not yet started and try to cancel those in progress).
To implement #1 I first tried using a bounded BlockingQueue to hold
the output from an ExecutorCompletionService. Unfortunately, an ECS
confronting a full BQ won't wait for space, but will just discard the
result. So I ditched the ECS and used the ThreadPoolExecutor directly,
arranging for the tasks to put their own results on the BQ and to wait
for space if necessary. That looked promising, but ...
... still didn't solve #2. A client trying to retrieve a result
from an empty BlockingQueue will wait, and that's fine. But I wanted
to distinguish between "Wait, something's coming" and "Nothing's in
the pipeline." The BQ could handle the first condition, but not the
two conditions combined.
I considered abandoning #2 and placing the burden on the clients:
They know how many tasks they submitted, so they should know how many
results to reap, right? But #3 makes this untenable: If you shut down
a ThreadPoolExecutor forcibly, all the running worker threads get
InterruptedExceptions. If some of those threads were interrupted while
waiting to put results on the BlockingQueue, those results get lost.
That's no tragedy in the context of a forcible shutdown, but it throws
off the clients' count of "How many results can we reap?" and you could
wind up waiting forever. Also, a forcible shutdown wouldn't awaken a
client already waiting on an empty BQ, and he'd be stuck indefinitely.
Eventually I settled on a plain Queue with explicit synchronization:
very old-fashioned and out of style, I know, but I couldn't think of a
way to do things in a more modern mode. It doesn't seem to me that my
goals #1,2,3 are outrageously weird, and there *ought* to be a way to
satisfy them without making myself look like a refugee from the last
millennium. Does anyone have suggestions?
--
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
Back to comp.lang.java.programmer | Previous | Next — Next in thread | Find similar | Unroll thread
To BlockingQueue or not to BlockingQueue? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-11-13 09:13 -0500
Re: To BlockingQueue or not to BlockingQueue? Eric Douglas <e.d.programmer@gmail.com> - 2015-11-13 07:29 -0800
Re: To BlockingQueue or not to BlockingQueue? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-11-13 10:41 -0500
Re: To BlockingQueue or not to BlockingQueue? Eric Douglas <e.d.programmer@gmail.com> - 2015-11-13 07:57 -0800
Re: To BlockingQueue or not to BlockingQueue? Kevin McMurtrie <mcmurtrie@pixelmemory.us> - 2015-11-13 16:56 -0800
Re: To BlockingQueue or not to BlockingQueue? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-11-14 17:08 -0500
Re: To BlockingQueue or not to BlockingQueue? Arne Vajhøj <arne@vajhoej.dk> - 2015-11-13 21:40 -0500
Re: To BlockingQueue or not to BlockingQueue? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-11-14 17:24 -0500
Re: To BlockingQueue or not to BlockingQueue? Arne Vajhøj <arne@vajhoej.dk> - 2015-11-14 19:13 -0500
Re: To BlockingQueue or not to BlockingQueue? Steven Simpson <ss@my.domain.invalid> - 2015-11-15 10:37 +0000
Re: To BlockingQueue or not to BlockingQueue? Sebastian <news@seyweiler.dyndns.org> - 2015-11-16 01:00 +0100
csiph-web