Reputation: 11
I would like to know why a given thread has been interrupted. Was it interrupted by me (part of my code), by other library or by any other reason?
Right now I can interrupt a Thread by
Thread.interrupt()
cancel a Future by
Future.cancel(boolean mayInterruptIfRunning)
shutdown a Executor by
ExecutorService.shutdown() or ExecutorService.shutdownNow()
but, none of them give me an option to send a reason (information why interruption was performed). In other words I cannot throw and catch InterruptedException with more detailed message or cause.
EDIT: Based on Glains solution I've prepared a similar one but with using a Callable
public class MyCallable<T> implements Callable<T> {
private final Callable<T> callable;
private volatile Thread thread;
private volatile String interruptReason;
public MyCallable(final Callable<T> callable) {
this.callable = callable;
this.thread = null;
}
@Override
public T call() throws Exception {
this.thread = Thread.currentThread(); // not getCurrentThread()
try {
return callable.call();
}
catch (InterruptedException e) {
System.out.println("Thread is interrupted: " + this.interruptReason);
}
}
public void interrupt(String interruptReason) {
this.interruptReason = interruptReason;
thread.interrupt();
}
}
Upvotes: 1
Views: 533
Reputation: 2873
You would have to write a custom API for that, as the Thread
cannot be aborted with a specific reason. To make a Runnable
able to be interrupted, you could create a custom interface that offers this functionality:
public interface Interruptable {
default void interrupt() {
interrupt(Reason.unknown());
}
void interrupt(Reason reason);
}
The defined reason can be anything, but the following may fit your use case:
public class Reason {
public static Reason unknown() {
return new Reason("unknown");
}
private final String reason;
public Reason(String reason) {
this.reason = reason;
}
public String getReason() {
return reason;
}
}
Now, you would have to tweak your Runnable
implementation so it can be interrupted. Please note that the following solution interrupts the thread gracefully, which means that the current iteration will finish, but a new one will not be started. If you want to truely interrupt the thread, you would need to store a reference to the thread executing the Runnable
instances run
method, since the interrupt
method will not be called from the same thread. Then you can call Thread.interrupt
on that reference.
public class MyRunnable implements Runnable, Interruptable {
private final AtomicBoolean running = new AtomicBoolean(false);
@Override
public void interrupt(Reason reason) {
running.set(false);
System.out.println("Thread is interrupted: " + reason.getReason());
}
@Override
public void run() {
running.set(true);
while (running.get()) {
// do work
}
}
}
Upvotes: 1