[concurrency-interest] Hung progress in ThreadPoolExecutor ExecutorCompletionService when slave threads killed.
dawid.weiss at gmail.com
Mon May 14 02:59:51 EDT 2012
Thanks for the discussion.
I was thinking much like Heinz -- that the lock should be reacquired
(and was surprised that it wasn't). David's arguments are clear to me
While thread.stop() is an ugly, ugly way to fix stuff there is really
no alternative to it if you have a situation in which you run
third-party code and you don't want to allow any background threads to
survive (other than spawning a separate jvm, but that's another
issue). It is an interesting use case on its own -- what I need is a
facility like a "domain context" that could be shut down when no
longer needed. But with executors it is nearly impossible -- even if
you run in a separate class loader that could be gc-ed entirely, if an
executor is stored in a static reference, it keeps refs to slave
threads and these in turn cannot be killed (when they're interrupted
new ones fill up the thread buffer again). Of course it's also
possible to create a "chuck norris" type code which cannot (or is hard
to) be killed (catching ThreadDeath, respinning in a try-catch) but
this is rather uncommon while executors are everywhere.
There seems to be no way to clean up the slave threads and thus
somehow close the pool (interrupting them just refills the buffer with
new ones). Sure, I could override bootclasspath or do runtime bytecode
rewriting trickery to detect when executors are created (and then
shutdown them nicely) but it is so dirty and doesn't really protect
against similar situations in custom code. Eh.
On Mon, May 14, 2012 at 7:23 AM, David Holmes <davidcholmes at aapt.net.au> wrote:
> Dr Heinz M. Kabutz writes:
>> When you stop() a thread that has called wait(), it first reacquires
>> the monitor before bailing out. The monitor is then automatically
>> unlocked again when you leave the scope.
> This is possible because the monitor reacquisition happens in the VM's
> native code, not part of any Java code sequence.
>> However, Condition.await() does *not* reacquire the lock when you
>> stop() the thread. When unlock() is then called on Lock as you exit
>> the scope, an IllegalMonitorStateException is then thrown. I would
>> love to know if that is deliberate or a coding bug?
> It is unavoidable due to the fact this is implemented in Java code. People
> will say "put the lock re-acquisition in a finally block, that will fix it",
> but that will only fix the case where the stop() hits while the thread is
> actually blocked. If the stop() hits during any of the queue management code
> you can easily get corrupt data structures.
> It is impractical, if not impossible, to non-trivial write async-exception
> safe code.
>> Anyway, my bet is that this is the culprit. You can also see the
>> await() method in the stack trace.
>> On 14/05/2012, Zhong Yu <zhong.j.yu at gmail.com> wrote:
>> > If an exception can occur any where any time, it is impossible to
>> > write code that can survive it and maintain invariants.
>> > lock
>> > x++;
>> > y++;
>> > unlock
>> > If we have to worry that some exception may be thrown between x++ and
>> > y++, we cannot write any program at all.
>> > ThreadDeath is exactly such an exception.
>> > Others include OutOfMemoryError and StackOverflowError - they are more
>> > predictable, but still, we cannot afford to worry about them on every
>> > `new` and every method call.
>> > Zhong Yu
>> > _______________________________________________
>> > Concurrency-interest mailing list
>> > Concurrency-interest at cs.oswego.edu
>> > http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>> Dr Heinz M. Kabutz (PhD CompSci)
>> Author of "The Java(tm) Specialists' Newsletter"
>> Sun Java Champion
>> IEEE Certified Software Development Professional
>> Tel: +30 69 75 595 262
>> Skype: kabutz
>> Concurrency-interest mailing list
>> Concurrency-interest at cs.oswego.edu
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
More information about the Concurrency-interest