Why is my sleeping thread not being interrupted? - java

I want to interrupt a sleeping thread, but it throws InterruptedException and doesn't stop. When I put Thread.interrupt() to the catch block, it interrupts the thread, but not from the first try.
I have a message, which must be written to file, when the thread is interrupted, but it write this message about 4-5 times. So I understand that thread is not interrupted at once. Why is it so, and what do I have to do?
My code has variable count of threads which changes at run-time. Each thread call method printAndDelay, which makes record to file and sleep. But I must have opportunity to stop any thread in any moment from main thread and record reason of stop to the same file.
void printAndDelay(String message, int delay)
{
try {
writeToLogFile(message, logFileName);
Thread.sleep(delay);
}
catch (InterruptedException e)
{
writeToLogFile("The reason of cancelling", logFileName);
Thread.currentThread().interrupt();
}
}
I try to interrupt thread by this code:
void stopOrder(String threadName)
{
Map<Thread, StackTraceElement[]> threads = Thread.getAllStackTraces();
threads.keySet().stream()
.filter(k -> k.getName().equalsIgnoreCase(threadName))
.findFirst()
.get()
.interrupt();
}
and I see that I can find this thread, but it throws InterruptException but doesn't stop thread. So I tried to stop it by putting Thread.interrupt() into the catch block.

For the message to be printed 4-5 times, you presumably have some loop which is calling printAndDelay multiple times:
for (Object obj : someList)
{
printAndDelay("hello", 1000);
}
Rather than dealing with the exception within printAndDelay, declare it as thrown in the method signature and deal with it from where the method is called.
void printAndDelay(String message, int delay) throws InterruptedException
{
writeToLogFile(message, logFileName);
Thread.sleep(delay);
}
You would alter your loop like so:
try
{
for (Object obj : someList)
{
printAndDelay("hello", 1000);
}
}
catch (final InterruptedException e)
{
writeToLogFile("The reason of cancelling", logFileName);
}
If "the reason of cancelling" is not a constant, you may want to wrap the InterruptedException in some other exception type, possibly a custom one, to pass the message upwards.

You need to do it like this. Stop the execution of the thread by throwing the InterruptedException.
void printAndDelay(String message, int delay) throws InterruptedException {
try {
writeToLogFile(message, logFileName);
Thread.sleep(delay);
} catch (InterruptedException e) {
writeToLogFile("The reason of cancelling", logFileName);
// propagate the exception
throw e;
}
}
And in the run method you need to restore the interrupt status.
public void run() {
try {
// whatever you want to do
printAndDelay(.....
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
The reason why I throw the InterruptedException and don't wrap it in another exception is that I want to restore the interrupt of the thread in the run method. You can even restore the interrupt right in the method and then throw some custom exception or a RuntimeException and stop the execution of your thread.

Related

Thread with interruption in java

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.

why doesnt thread.sleep stop at the first catch?

public static void main(String s[])
{
Thread t=Thread.currentThread();
t.setName("main");
try
{
for(int i=0;i<=5;i++)
{
System.out.println(i);
Thread.sleep(1000);//interrupted exception(System provides error on its own)
}
}
catch(InterruptedException e)
{
System.out.println("main thread interrupted");
}
}
`In my understanding when there is an exception condition the control goes to the catch, implements it and leaves the code. when we use thread.sleep and create a catch for interruptedException why does it keeps on running? instead of quitting . This is the code, when for loop runs for the first time, it prints "0" the when it encounters thread.sleep hence an interruptedexception, shouldnt it go to catch and execute S.O.P and terminate?
why does it keeps on running?
Your program doesn't terminate unless you tell it to. It normally keeps on running. Triggering an exception doesn't change that.
Just calling Thread.sleep doesn't trigger an InterruptedException. For this code to throw an InterruptedException something would have to call interrupt on the thread. Change the code to
public class MainInterruptingItself {
public static void main(String s[]) {
Thread.currentThread().interrupt();
try {
for(int i=0;i<=5;i++) {
System.out.println(i);
Thread.sleep(1000);
}
}
catch(InterruptedException e) {
System.out.println("main thread interrupted");
}
}
}
and it will print out
0
main thread interrupted
What happens here is that calling interrupt sets the interrupt flag on the thread. When Thread.sleep executes it sees that the interrupt flag is set and based on that throws an InterruptedException.

future.cancel does not work

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.

InterruptedException thrown from futures

Suppose I have a method as follows:
public void poll(Callable<Boolean> callable) {
ScheduledExecutorService service = Executors.newSingleThreadedScheduledExecutor();
Future<Boolean> future = service.schedule(callable, 0L, TimeUnit.MILLISECONDS);
try {
while (!future.get()) {
future = service.schedule(callable, 5L, TimeUnit.MINUTES);
}
} catch (ExecutionException e) {
// ...
} catch (InterruptedException e) {
// ...
} finally {
service.shutdown();
}
}
How does an InterruptedException ever get thrown (and caught in poll())? Anything thrown by the callable (including InterruptedException, right?) would be an ExecutionException, we never cancel any futures, and the service's shutdownNow() is never called.
Aside: being what it is, is it possible to make this polling method more bulletproof against things like InterruptedException?
The InterruptedException would be thrown by get while waiting (blocking) for the callable to finish.
I'm not sure what you mean by bulletproof, you have to handle the possibility of the exception being thrown.
InterruptedException can be thrown by the thread which called get and is waiting for completion, not by the callable

How to interrupt BlockingQueue?

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.

Categories

Resources