Can continuation support finally solve the "How do I stop this thread" problem?

Archie Cobbs archie.cobbs at gmail.com
Wed Aug 31 21:50:17 UTC 2022


This question is somewhat tangential to Loom but I thought I'd ask in case
the answer is an easy yes or no.

Lately I've been reviewing various attempts at intra-JVM Java "sandboxing",
none of which are fully satisfying. I think this is a missed opportunity
for Java in general, but that's a separate discussion.

The term "sandbox" has various meanings but for this question think of it
simply as what you would need (for example) to build a web site that hosted
a live JShell console for educational purposes but all running within a
single JVM (there are some examples of this out there like tryjshell.org
but those use separate processes or Docker). Obviously, execution of
arbitrary Java code from random people on the Internet would have to be
strictly controlled, and therefore JShell's ExecutionControl would have to
run the code in some kind of airtight sandbox.

I just want to focus on one small aspect of doing this: A basic requirement
of such a sandbox is the ability to stop a running thread. But currently
there's no 100% reliable way to do this in Java, even if you can rewrite
the bytecode, because it's impossible to unblock a thread blocked in
certain system calls.

What about Thread.stop()? It only works sometimes. Plus it's deprecated
(side node, the stated reasons for deprecating this method never made sense
to me, because the trade-offs should be left to the programmer to evaluate,
and moreover ThreadDeath is no more unsafe than StackOverflowError, which
programmers seem to throw all the time :)

FYI here's a simple example showing a thread that can't be stopped no
matter what we try:

public class ThreadNoStop {
    public static void main(String[] args) throws Exception {

        // Start unstoppable thread
        final Thread thread = new Thread(() -> {
            System.out.println("thread: reading stdin...");
            try {
                System.in.read();
            } catch (Throwable t) {
                System.out.println("thread: caught exception: " + t);
            }
            System.out.println("thread: done reading stdin...");
        });
        thread.start();

        // Try to kill it any way possible
        Thread.sleep(500);
        System.out.println("main: invoking interrupt()...");
        thread.interrupt();
        System.out.println("main: invoking stop()...");
        thread.stop();
        System.out.println("main: closing System.in...");
        System.in.close();   // hangs here until there's input
        System.out.println("main: joining thread...");
        thread.join();
        System.out.println("main: done.");
    }
}

[JEP 425 Virtual Threads] states:

> The implementations of the networking APIs in the java.net and
java.nio.channels packages now work with virtual threads: An operation on a
virtual thread that blocks to, e.g., establish a network connection or read
from a socket, releases the underlying platform thread to do other work.

This makes it sounds like basically every blocking method is going to have
to be adapted so that its state can be "detached" from the platform thread
for continuation purposes...? If so, great!

My question is this: could this work be leveraged to also finally solve the
"How do I stop this thread" problem?

Even if this new mechanism only worked for virtual threads (or only for
platform threads) it would still be a big improvement.

Again, my opinion here but it seems like there really ought to be some
official equivalent of Process.destroyForcibly() for Java threads.... it's
a basic control/fail-safe.

On a related note - will [JEP 428 Structured Concurrency] guarantee that
exiting a StructuredTaskScope never hangs indefinitely?? I guess not..

But a better stop mechanism would allow it to make that nice guarantee.
This would give it an "automatic cleanup" feature analogous to how
try-with-resources automatically hides any extra exceptions thrown by
close().

We could also then add a new method ExecutorService.forceShutdown()...

This seems like an obvious missing piece to me.

Thoughts?

-Archie

-- 
Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20220831/64ffd455/attachment.htm>


More information about the loom-dev mailing list