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.
Related
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.
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();
}
}
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.
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.
I'm trying to understand how threads work in Java and currently investigating how to implement looped threads that can be cancelled. Here's the code:
public static void main(String[] args) throws Exception {
Thread t = new Thread() {
#Override
public void run() {
System.out.println("THREAD: started");
try {
while(!isInterrupted()) {
System.out.printf("THREAD: working...\n");
Thread.sleep(100);
}
} catch(InterruptedException e) {
// we're interrupted on Thread.sleep(), ok
// EDIT
interrupt();
} finally {
// we've either finished normally
// or got an InterruptedException on call to Thread.sleep()
// or finished because of isInterrupted() flag
// clean-up and we're done
System.out.println("THREAD: done");
}
}
};
t.start();
Thread.sleep(500);
System.out.println("CALLER: asking to stop");
t.interrupt();
t.join();
System.out.println("CALLER: thread finished");
}
The thread I create is indended to be interrupted sooner or later. So, I check isInterrupted() flag to decide whether I need to go on and also catch InterruptedException to handle cases when I'm in a kind of waiting operation (sleep, join, wait).
Things I'd like to clarify are:
Is it fine to use interruption mechanism for this kind of task? (comparing to having volatile boolean shouldStop)
Is this solution correct?
Is it normal that I swallow InterruptedException? I'm not really interested what was the piece of code where someone asked my thread to interrupt.
Are there any shorter ways to solve this problem? (the main point is having 'infinite' loop)
EDIT
Added call to interrupt() in catch for InterruptedException.
I am answering no. 3:
Basically the question is: What purpose does an Interrupted exception have? It tells you to stop blocking (e.g. sleeping) and return early.
There are two ways dealing with an InterruptedException:
Rethrow it, so the thread remains interrupted
set Thread.currentThread.interrupt() again and do your cleanup work. This way you can be sure that another method in your thread starting to sleep will throw again
Simply swallowing an InterruptedException is not a good idea regarding the purpose of such an interrupt which is to finally terminate. But you are only asked to interrupt so you still have time to clean up.
In this case this might be an 'overreaction' of myself, but typically such code is much more complicated and how do you know, that some follow-up-code in this Thread would not call a blocking method again?
EDIT
Otherwise I think what you're doing is fine. For me a bit surprising, though, because I never saw anyone in his own code actually doing it.
And interesting article explaining why can be found here: http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html
Yes, it's fine. You should document how a Thread/Runnable must be stopped. You could add a dedicated stop method on your Runnable implementation that encapsulates the stopping mechanism. Either use interrupt, or use a dedicated boolean value, or both.
Yes, except the good practice is to restore the interrupt status when catching InterruptedException: Thread.currentThread().interrupt();
No, you should restore the interrupt status
None that I'm aware of
1) The way in your example is preferable to using a volatile flag (which is redundant since you already have the interrupted flag), according to the Java Concurrency in Practice book. It is how InterruptedExceptions were intended to be used.
2) Yes
3) you can eat the exception as long as you restore the interrupt flag status. The exception doesn't represent an error so eating it doesn't lose any information, it is purely a means of transferring control. (Restoring the interrupt flag status is important for cases where you have nested control structures that each need to be informed that the thread is cancelling, for a simple example like yours it's good form but if it's missing it won't hurt anything.)
4) no
It's fine to use Interruption, but use them well. You have to re-throw Thread.currentThread().interrupt() in your catch. Here is a piece of code showing why :
public class MyThread extends Thread {
private static boolean correct = true;
#Override
public void run() {
while (true) {
// Do Something 1
for (int i = 0; i < 10; i++) { // combined loop
// Do Something 2
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
if (correct)
Thread.currentThread().interrupt(); // reinterrupting
System.out.println("First Catch");
break; // for
}
}
try {
// Do Something 3
System.out.print("before sleep, ");
Thread.sleep(1000);
System.out.print("After sleep, ");
} catch (InterruptedException ex) {
if (correct)
Thread.currentThread().interrupt();
System.out.println("Second catch");
break; // while
}
}
System.out.println("Thread closing");
}
private static void test() throws InterruptedException {
Thread t = new MyThread();
t.start();
Thread.sleep(2500);
t.interrupt();
t.join();
System.out.println("End of Thread");
}
public static void main(String[] args)
throws InterruptedException {
test();
correct = false; // test "bad" way
test();
}
}
Another thing is, Interruptions don't always work when waiting on InputStreams. You then can use (for some) InterruptedIOException, but it won't always work. To understand these cases, you might want to try this piece of code :
public class Mythread extends Thread {
private InputStream in;
public Mythread(InputStream in) {
this.in = in;
}
#Override
public void interrupt() {
super.interrupt();
try {
in.close(); // Close stream if case interruption didn't work
} catch (IOException e) {}
}
#Override
public void run() {
try {
System.out.println("Before read");
in.read();
System.out.println("After read");
} catch (InterruptedIOException e) { // Interruption correctly handled
Thread.currentThread().interrupt();
System.out.println("Interrupted with InterruptedIOException");
} catch (IOException e) {
if (!isInterrupted()) { // Exception not coming from Interruption
e.printStackTrace();
} else { // Thread interrupted but InterruptedIOException wasn't handled for this stream
System.out.println("Interrupted");
}
}
}
public static void test1() // Test with socket
throws IOException, InterruptedException {
ServerSocket ss = new ServerSocket(4444);
Socket socket = new Socket("localhost", 4444);
Thread t = new Mythread(socket.getInputStream());
t.start();
Thread.sleep(1000);
t.interrupt();
t.join();
}
public static void test2() // Test with PipedOutputStream
throws IOException, InterruptedException {
PipedInputStream in = new PipedInputStream(new PipedOutputStream());
Thread t = new Mythread(in);
t.start();
Thread.sleep(1000);
t.interrupt();
t.join();
}
public static void main(String[] args) throws IOException, InterruptedException {
test1();
test2();
}
}