Interrupt a sleeping thread
Trying to interrupt a running thread, in this example, t1, which is executed by a thread in a thread pool.
t2 is the one that sends the interrupt.
I'm unable to stop the running t1, t1 does not get Interrupte开发者_如何学运维dException.
What am I missing?
Executor exec1 = Executors.newFixedThreadPool(1);
// task to be interrupted
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
System.out.println("starting uninterruptible task 1");
Thread.sleep(4000);
System.out.println("stopping uninterruptible task 1");
} catch (InterruptedException e) {
assertFalse("This line should never be reached.", true);
e.printStackTrace();
}
}
};
final Thread t1 = new Thread(runnable);
// task to send interrupt
Runnable runnable2 = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
t1.interrupt();
System.out.println("task 2 - Trying to stop task 1");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t2 = new Thread(runnable2);
exec1.execute(t1);
t2.start();
t2.join();
Seems like you misunderstand threads and Executors. You create two threads object for two runnables, but start only one of them (t2), t1 you pass to Executor to run inside it. But executor does not need Thread to be supplied -- it just need Runnable implementation. Executor itself is a thread pool (usually, but it's not required), and it just creates (and pool) threads inside it. It sees you thread just as simple Runnable (which is Thread implements). So you actualy send interrupt to the thread which was never started.
If you really want to make your code works, you should remove Executor, and just start both threads explicitly.
Your mistake is that you're trying to execute a Thread
on a ThreadPool
.
This appears to work, because Thread
happens to implement Runnable
, but because the thread is only being used as a Runnable
and is not started as a Thread
, calling methods like #interrupt()
won't have the desired effect.
If you still need to use a thread pool, you should instead look into using a class like FutureTask
. Wrap your Runnable
in a FutureTask
, and then submit the task to a thread pool. Then, when you want to interrupt the task, call futureTask.cancel(true)
.
The problem is that you can never really know which thread would be used by the Executor
to run your task.
Even though you have submitted a Thread
object, The Executor will use the thread created by the fixed thread pool. Thus the thread with reference t1
is not the thread in which your task is going to be executed. so calling t1.interrupt()
is not going to do anything.
To properly way to do this is to use an ExecutorService
and use the submit()
to submit a Runnable
/Callable
object. This will return a Future
which exposes a cancel()
method which can be used to cancel the task.
Calling Thread.interrupt does not necessarily throw an InterruptedException. It may just set the interrupted state of the thread, which can be polled by Thread.interrupted() or Thread.isInterrupted.
See http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html#interrupt() for more details.
To interrupt the executor thread ,
final ExecutorService exec1 = Executors.newFixedThreadPool(1);
final Future<?> f = exec1.submit(runnable);
...
f.cancel(true);
精彩评论