As per the Java documentation:
Interrupting a thread that is not alive need not have any effect.
Particularly, interrupting a thread between the call to start() and the invocation of run() has no effect.
So I wrote a Thread
which can be interrupted even before it started, so that the interrupted state is communicated once it started:
/**
* A thread that can be interrupted before actually starting (that is between the moment {@link
* #start} is called and {@link #run} is invoked.
*/
public final class InterruptableThread extends Thread {
private final AtomicBoolean mInterrupted = new AtomicBoolean(false);
private final Object mLock = new Object();
private final AtomicBoolean mStarted = new AtomicBoolean(false);
public InterruptableThread(Runnable runnable) {
super(runnable);
}
@Override
public void run() {
synchronized (mLock) {
mStarted.set(true);
if (mInterrupted.get()) {
super.interrupt();
}
}
super.run(); // Let the original runnable handle the interruption by itself.
}
@Override
public void interrupt() {
synchronized (mLock) {
mInterrupted.set(true);
if (mStarted.get()) {
super.interrupt();
}
}
}
}
It seems safe to me, although the AtomicBoolean
are maybe not required. But because we're dealing with multithreading here, another point of view is welcome.
I need this in a library with start()
and stop()
methods which look like:
public void start() {
synchronized (mStartStopLock) {
myThread = new InterruptableThread(myRunnable);
myThread.start();
}
}
public void stop() {
synchronized (mStartStopLock) {
myThread.interrupt();
myThread.join();
}
}
As you can see, despite the lock, if start()
and stop()
are called immediately one after another, nothing guarantees that interrupt()
will have effect on the thread if it's a regular Java Thread
. That's important because the Runnable
uses the interrupted status for stopping itself.
ExecutorService
and get aFuture
when submitting jobs. You can.cancel
aFuture
before it starts. \$\endgroup\$ – markspace Sep 17 '19 at 0:46