I am trying to understand interrupting threads within an ExecutorService and I can't figure out why the following MyNeverEndingRunnable class doesn't get the interrupt signal. I have a class that implements Runnable and simply prints and waits in a loop until it is interrupted:
class MyNeverEndingRunnable
implements Runnable
{
int count = 0;
#Override
public void run()
{
while (true)
{
System.out.printf("[%d]:%d\n", Thread.currentThread().getId(), ++count);
try { Thread.sleep(5000L); } catch (Exception ignored) {}
if (Thread.interrupted())
{
break;
}
}
}
}
I spawn a few of these threads then call shutdownNow() on my ExecutorService which should call interrupt on each of the running threads but the below code continues to run forever:
int threadCount = 5;
ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
Future[] threads = new Future[threadCount];
for (int k = 0; k < threadCount; ++k)
{
threads[k] = executorService.submit(new MyNeverEndingRunnable());
}
Thread.sleep(20000L);
executorService.shutdownNow();
while (!executorService.isShutdown()) Thread.sleep(1000L);
Does anyone know what I am doing wrong here?
From the Javadoc:
InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown. [My emphasis]
NB There's nothing that actually guarantees that threads are interrupted by shutdownNow(). It just describes that as a 'typical implementation'.
Your code is a little strange. Try this:
try
{
Thread.sleep(5000L);
}
catch (InterruptedException exc)
{
break;
}
and remove the Thread.interrupted() test.
Read the Javadoc on Thread.sleep():
Throws:
...
InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.
As soon as the exception is thrown, it's no longer interrupted. In your case, you can immediately break out of the loop and let the thread die, as #EJP suggested. But if your code doesn't have ownership of the thread (e.g. a separate method), you'll want to make sure the interruption is propagated to the caller, either by propagating the exception, or by re-interrupting:
try {
while (true) {
System.out.printf("[%d]:%d\n", Thread.currentThread().getId(), ++count);
Thread.sleep(5000L);
}
} catch (InterruptedException notIgnored)
Thread.currentThread().interrupt();
}
Or similarly:
while (!Thread.currentThread().isInterrupted()) {
System.out.printf("[%d]:%d\n", Thread.currentThread().getId(), ++count);
try {
Thread.sleep(5000L);
} catch (InterruptedException notIgnored)
Thread.currentThread().interrupt();
}
}
Related
I have a question about threads in Java.
I have the following code:
public static void main(String[] args) {
Runnable r = () -> {
while (!Thread.interrupted()) {
System.out.println("Hola");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("interrupted");
break;
}
}
};
Thread t = new Thread(r);
t.start();
try {
Thread.sleep(2000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
t.interrupt();
}
Why if I introduce an interrupt does it still enter the loop? (without break).
I understand the operation of the thread when there is an exception.
Whenever the sleep method detects an interruption it resets the interrupt flag before throwing an InterruptedException. So if you don't use break then the interrupt flag is set to false by the time the exception is caught and the while loop test never detects the interruption.
The recommended practice is to add a line to your catch block like this
Thread.currentThread.interrupt();
if you want to keep the interrupt status.
It's not a problem here but be aware that Thread.interrupted() resets the interrupt flag. It's a convenience method used by some JDK code so that resetting the interrupt flag and throwing the exception takes less code.
I have a nice and compact code, which does not work as I expected.
public class Test {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
for (;;) {
}
} finally {
System.out.println("FINALLY");
}
}
};
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(r);
try {
future.get(3, TimeUnit.SECONDS);
} catch (TimeoutException e) {
boolean c = future.cancel(true);
System.out.println("Timeout " + c);
} catch (InterruptedException | ExecutionException e) {
System.out.println("interrupted");
}
System.out.println("END");
}
}
The output is :
Timeout true
END
Question:
Why does not terminate the future.cancel(true) method the called Runnable?
After the program wrote the "END" to the output, the "r" Runnable is still running.
The problem is that your Runnable is not interruptible: task interruption is a collaborative process in Java and the cancelled code needs to check regularly if it's been cancelled, otherwise it won't respond to the interruption.
You can amend you code as follows and it should work as expected:
Runnable r = new Runnable() {
#Override public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {}
} finally {
System.out.println("FINALLY");
}
}
};
This is always a little bit misleading: The ExceutorService or even the underlying thread scheduler do not know anything about what the Runnable is doing. In your case they don't know that there is a unconditional loop.
All these methods (cancel, done, ...) are related to manage Threads in the Executor structure. cancel cancels the thread from the point of view of the Executor service.
The programmer must test if the Runnable was canceled and must terminate the run() method.
So in your case (if I remember well) something like this:
public class Test {
public static void main(String[] args) {
FutureTask r = new FutureTask () {
#Override
public void run() {
try {
for (;!isCancelled();) {
}
} finally {
System.out.println("FINALLY");
}
}
};
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(r);
try {
future.get(3, TimeUnit.SECONDS);
} catch (TimeoutException e) {
boolean c = future.cancel(true);
System.out.println("Timeout " + c);
} catch (InterruptedException | ExecutionException e) {
System.out.println("interrupted");
}
System.out.println("END");
}
}
When you cancel a Future whose Runnable has already begun, the interrupt method is called on the Thread that is running the Runnable. But that won't necessarily stop the thread. Indeed, if it's stuck in a tight loop, like the one you've got here, the Thread won't stop. In this case, the interrupt method just sets a flag called the "interrupt status", which tells the thread to stop when it can.
See the Javadoc for the interrupt method of Thread
Future.cancel() will cancel any queued task or will call Thread.interrupt() on your thread if already running.
You need to interrupt your code
It's your code's responsibility is to be ready for any interruptions. I'd go so far to say that whenever you have a long running task, that you insert some interrupt ready code like this:
while (... something long...) {
... do something long
if (Thread.interrupted()) {
... stop doing what I'm doing...
}
}
How to stop what I'm doing?
You have several options:
If your you are in Runnable.run() just return or break out of the loop and finish the method.
You may be in some other method deep in the code. It may make sense at that point for that method to throw InterruptedException so you would just do that (leaving the flag cleared).
But maybe deep in your code it doesn't make sense to throw InterruptedException. In that case you should throw some other exception, but before that mark your thread interrupted again so the code that catches knows that an interrupt was in progress. Here's an example:
private void someMethodDeepDown() {
while (.. long running task .. ) {
... do lots of work ...
if (Thread.interrupted()) {
// oh no! an interrupt!
Thread.currentThread().interrupt();
throw new SomeOtherException();
}
}
}
Now the exception can propagate an either terminate the thread or be caught, but the receiving code hopefully notices that an interrupt is in progress.
This code hangs. I understand that I call future.get() for the future that wasn't executed but I expect to see CancellationExcetpion or InterruptedException or some other exception on future.get() method. Am I wrong?
public class ExecutorTest {
static ExecutorService executorService = Executors.newFixedThreadPool(1);
public static void main(String[] args) throws Exception {
List<Future> futures = new ArrayList<Future>();
for (int i = 0; i < 10; i++) {
Future<Object> future = executorService.submit(new Callable<Object>() {
#Override
public Object call() throws Exception {
System.out.println("Start task");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Finish task");
return "anything";
}
});
futures.add(future);
}
new Thread() {
#Override
public void run() {
try {
Thread.sleep(10000);
System.out.println("Shutdown Now");
executorService.shutdownNow();
} catch (InterruptedException e) {
System.out.println("Interrupted Exception during shutdown");
}
}
}.start();
for(Future f : futures) {
System.out.println("-------------------------");
System.out.println("before sleep");
Thread.sleep(3000);
System.out.println("after sleep...");
try {
f.get();
} catch (Exception ex) {
System.out.println("exception during future.get");
}
System.out.println("after get!");
}
}
}
This is my output
Start task
-------------------------
before sleep
after sleep...
Finish task
after get!
-------------------------
Start task
before sleep
after sleep...
Finish task
Start task
after get!
-------------------------
before sleep
after sleep...
Finish task
Start task
after get!
-------------------------
before sleep
Shutdown Now
Finish task
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at ru.pp.ExecutorTest$1.call(ExecutorTest.java:28)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
after sleep...
after get!
-------------------------
before sleep
after sleep...
Java 8, Intellij
If I replace
System.out.println("Start task");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
with this
System.out.println("Start task");
Thread.sleep(3000);
then it doesn't hang
I'm frustrated...
When you invoke shutdownNow, the ExecutorService removes any scheduled, but not yet run, tasks and returns them to you as a List<Runnable>. These tasks have a corresponding Future which you already have a reference to. Since these tasks are never run, they never produce a result, ie. never complete. As such, the Future#get() for those tasks will never return.
If you wanted to, you could return run those tasks with
executorService.shutdownNow().forEach(r -> r.run());
and you would see your all Future#get() calls return.
You should probably only call Future#get() if you know the task is done/cancelled. Alternatively, give it a timeout.
When Thread_1 calls FutureTask#get then Thread_1#wait is called. Now to continue Thread_1 it should be notified by somebody. Notification is called ONLY when FutureTask is terminated (on FutureTask#set, FutureTask#setException or FutureTask#cancel). But in my case the FutureTask was never started because of shutdownNow (FutureTask was in state NEW). So it was never terminated and Thread_1#notify was never called.
To fix it I got all not started futures from #shutdownNow and didn't call FutureTask#get for them.
PS: Honestly FutureTask uses sun.misc.Unsafe#park #unpark methods instead of wait and notify.
When i try to kill my Robber threads, some die , but some get stuck in the wait() block , what would be a better way to kill all the threads , or how do i get the blocked threads out to be killed?
private int robberId;
private static int robberGlobalId=0;
private TreasureChest chest;
private boolean alive = true;
public Robber(TreasureChest chest) {
robberId = robberGlobalId;
robberGlobalId++;
this.chest = chest;
}
public void run() {
while (alive) {
try {
synchronized(chest){
robCoin();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Robber " +robberId +" just died");
}
public void robCoin() throws InterruptedException {
if (chest.getTreasureAmount() <= 0 ) {
chest.wait();
} else {
chest.removeCoin();
}
Thread.sleep(50);
}
public void killRobber() {
alive = false;
}
When i try to kill my Robber threads, some die , but some get stuck in the wait() block , what would be a better way to kill all the threads ,
The right way to "kill" a thread is to interrupt it with thread.interrupt(). If the thread is blocked in a wait(...) call, this will immediately throw InterruptedException. When you catch InterruptedException it is a good idea to immediately re-interrupt the thread to preserve the interrupt flag because when the exception is thrown, the interrupt bit is cleared.
try {
...wait();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
// handle the interrupt
return;
}
Since not all methods throw InterruptedException, you can also check to make sure the thread has been interrupted with something like the following:
if (Thread.currentThread().isInterrupted()) {
// stop processing
return;
}
Or in your case something like:
while (alive && !Thread.currentThread().isInterrupted()) {
Btw, alive should be volatile because it looks to be accessed by multiple threads.
Interrupting the thread is one way to do it as demonstrated in #Gray's answer, however it might be cleaner to wake up waiting threads when you "kill" the Robber instead of interrupting them.
In this example below the "Robber task" (implemented by the run() method) will wait as long as the robber is alive and the chest is empty ( less than or equal to 0). If killRobber() is called waiting threads are woken up and exit run() gracefully (alive will be false).
public void run() {
try{
synchronized(chest){
while (chest.getTreasureAmount() <= 0 && alive) {
chest.wait();
}
if(alive){
chest.removeCoin();
}
}
}catch (InterruptedException ie){
/* Thread interrupted do something appropriate,
which may be to do nothing */
}
}
public void killRobber() {
synchronized(chest){
alive = false;
chest.notifyAll();
}
}
BlockingQueue.put can throw InterruptedException.
How can I cause the queue to be interrupting by throwing this exception?
ArrayBlockingQueue<Param> queue = new ArrayBlockingQueue<Param>(NUMBER_OF_MEMBERS);
...
try {
queue.put(param);
} catch (InterruptedException e) {
Log.w(TAG, "put Interrupted", e);
}
...
// how can I queue.notify?
You need to interrupt the thread that is calling the queue.put(...);. The put(...); call is doing a wait() on some internal condition and if the thread which is calling the put(...) gets interrupted, the wait(...) call will throw InterruptedException which is passed on by the put(...);
// interrupt a thread which causes the put() to throw
thread.interrupt();
To get the thread you can either store it when it is created:
Thread workerThread = new Thread(myRunnable);
...
workerThread.interrupt();
or you can use the Thread.currentThread() method call and store it somewhere for others to use to interrupt.
public class MyRunnable implements Runnable {
public Thread myThread;
public void run() {
myThread = Thread.currentThread();
...
}
public void interruptMe() {
myThread.interrupt();
}
}
Lastly, it is a good pattern when you catch InterruptedException to immediately re-interrupt the thread because when the InterruptedException is thrown, the interrupt status on the thread is cleared.
try {
queue.put(param);
} catch (InterruptedException e) {
// immediately re-interrupt the thread
Thread.currentThread().interrupt();
Log.w(TAG, "put Interrupted", e);
// maybe we should stop the thread here
}
You need to have a reference to the thread running the code with queue.put(), like in this test
Thread t = new Thread() {
public void run() {
BlockingQueue queue = new ArrayBlockingQueue(1);
try {
queue.put(new Object());
queue.put(new Object());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
};
t.start();
Thread.sleep(100);
t.interrupt();
Calling put will wait for a slot to be free before it adds the param and flow can continue.
If you capture the thread that is running when put is called (ie, call Thread t1 = Thread.currentThread() before calling put) and then in another thread call interrupt on this (whilst the t1 is blocked).
This example has something similar whereby it takes care of calling interrupt after a given timeout.