I made a simple function to test interrupt() & InterruptedException in Java:
public static void main(String[] args) {
checkInterrupt();
}
private static void checkInterrupt() {
Runnable runMe = new Runnable() {
#Override
public void run() {
for(int i=0; i<6; i++) {
System.out.println("i = "+i);
if(i==3) {
System.out.println("i==3, Thread = "+Thread.currentThread().getId());
//I invoke interrupt() on the working thread.
Thread.currentThread().interrupt();
}
}
}
};
Thread workingThread = new Thread(runMe);
System.out.println("workingThread("+workingThread.getId()+") interrupted 1 ? "+workingThread.isInterrupted());
workingThread.start();
try {
workingThread.join();
} catch (InterruptedException e) {
//I thought I should get InterruptedException, but I didn't, why?
System.out.println("workingThread("+workingThread.getId()+") is interrupted.");
}
System.out.println("workingThread("+workingThread.getId()+") interrupted 2 ? "+workingThread.isInterrupted());
}
As you see above, in run(), I interrupt the working thread by invoking Thread.currentThread().interrupt() when i==3. I thought my code should catch InterruptedException during workingThread.join(). But there is no exception at all. Why?
You'll get an InterruptedException if the thread calling join is interrupted while waiting for the other one to die. That's not what happens in your case - you're interrupting the thread you're joining which is an entirely different matter.
You are interrupting the wrong thread. From the documentation of Thread.join():
InterruptedException - if any thread has interrupted the current thread.
You are interupting the thread that is being joined, not the thread that is doing the joining (referred to as current thread in the documentation).
Try this instead
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread() {
public void run() {
while (true) {}
}
};
t.start();
Thread.currentThread().interrupt();
t.join();
}
Here is another variant, this time interrupting from the thread that is being joined.
public static void main(String[] args) throws InterruptedException {
final Thread mainThread = Thread.currentThread();
Thread t = new Thread() {
public void run() {
try {
Thread.sleep(10000);
mainThread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
t.join();
}
Related
I'm learning concurrency knowledge in Java. About volatile keyword, it should make variable visible in different threads. But in my demo code, it doesn't seem to work as expected. The method run() in the class which implements Runnable will never stop.
public class VisibilityDemo {
public static void main(String[] args) throws InterruptedException {
TimeConsumingTask timeConsumingTask = new TimeConsumingTask();
Thread thread = new Thread(new TimeConsumingTask());
thread.start();
Thread.sleep(3000);
timeConsumingTask.cancel();
}
}
class TimeConsumingTask implements Runnable {
private volatile boolean toCancel = false;
#Override
public void run() {
while (! toCancel) {
System.out.println("executing...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (toCancel) {
System.out.println("Task was canceled.");
} else {
System.out.println("Task done.");
}
}
public void cancel() {
toCancel = true;
System.out.println(this + " canceled.");
}
}
In your main method you have two instances of your task:
public static void main(String[] args) throws InterruptedException {
TimeConsumingTask timeConsumingTask = new TimeConsumingTask(); //<-- one
Thread thread = new Thread(new TimeConsumingTask()); //<-- two
thread.start();
Thread.sleep(3000);
timeConsumingTask.cancel(); //<-- cancel() on first
}
}
You're passing one to the Thread constructor and then call cancel on the other one. You need to call cancel on the instance passed to Thread, like so:
public static void main(String[] args) throws InterruptedException {
TimeConsumingTask timeConsumingTask = new TimeConsumingTask();
Thread thread = new Thread(timeConsumingTask); //<-- difference here
thread.start();
Thread.sleep(3000);
timeConsumingTask.cancel();
}
}
public class WaitNotifyAll {
private static volatile Object resourceA = new Object();
public static void main(String[] args) throws Exception {
Thread threadA = new Thread(new Runnable() {
#Override
public void run() {
synchronized (resourceA) {
try {
System.out.println("threadA begin wait");
resourceA.wait();
System.out.println("threadA end wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread threaB = new Thread(new Runnable() {
#Override
public void run() {
synchronized (resourceA) {
System.out.println("threadC begin notify");
threadA.interrupt();
resourceA.notify();
}
}
});
threadA.start();
Thread.sleep(1000);
threaB.start();
System.out.println("main over");
}
}
There are two possible result here:
throws InterruptedException
normal termination
why?
I don't understand. when threadA is interruptted ,result should throws InterruptedException. but sometimes execute this program, it can normal finish.
environment: java8, mac
When a thread receives both an interrupt and a notify, the behaviour may vary.
Please refer to https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.2.3
Credit - Alex Otenko on the Concurrency Interest mailing list
Because of reordering. In normal termination compiler reordered instruction interrupt and notify, interruption invokes on working thread and no interrupted exception throws.
Try to forbid reordering with reading volatile variable and you always get interrupted exception.
public class WaitNotifyAll {
private static volatile Object resourceA = new Object();
public static void main(String[] args) throws Exception {
Thread threadA = new Thread(new Runnable() {
#Override
public void run() {
synchronized (resourceA) {
try {
System.out.println("threadA begin wait");
resourceA.wait();
System.out.println("threadA end wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread threaB = new Thread(new Runnable() {
#Override
public void run() {
synchronized (resourceA) {
System.out.println("threadC begin notify");
threadA.interrupt();
System.out.print(resourceA);
resourceA.notify();
}
}
});
threadA.start();
Thread.sleep(1000);
threaB.start();
System.out.println("main over");
}
}
Say I have the following test:
#Test(timeout = 1)
public void test(){
while(true){}
}
This simulates a test that would take a long time to return, not from sleeping, but from raw calculation time. How does the test exit? If I create a thread and try the same thing, it does not compile.
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
try {
while (true) {
}
} catch (InterruptedException e) {//Exception 'java.lang.InterruptedException' is never thrown in the corresponding try block'
e.printStackTrace();
}
}
};
thread.start();
thread.interrupt();
}
I can even attempt to replicate the implementation, but it still does not interrupt the thread:
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
try {
doTest();
} catch (InterruptedException throwable) {
System.out.println("interrupted");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
private void doTest() throws Throwable {
while (true) {
}
}
};
thread.start();
thread.interrupt();
}
The java.lang.Exception: test timed out after 1 milliseconds exception claims to be originating strait from the while loop when running the regular test.
I am confused as to how the test is 'interrupted', but I cannot do the same with a regular thread. How is this 'interrupting' feature implemented in JUnit?
The code tells you the truth: https://github.com/junit-team/junit/blob/master/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java
I have two thread classes: one that prints numbers from 0 to 9, and another from 100 to 109. What I want is to make the first thread wait for the other one to finish. For this, I used the join() method, but it's not working. Please tell me where I'm going wrong:
//demonstrates the use of join() to wait for another thread to finish
class AThread implements Runnable {
Thread t;
AThread() {
t = new Thread(this);
}
public void run() {
try {
for (int i=0; i<10; i++) {
System.out.println(i);
Thread.sleep(10);
}
} catch (InterruptedException e) {
System.out.println(t + " interruped.");
}
}
public void halt(Thread th) {
try {
th.join();
} catch (InterruptedException e) {
System.out.println(t + " interruped.");
}
}
}
//a different thread class (we distinguish threads by their output)
class BThread implements Runnable {
Thread t;
BThread() {
t = new Thread(this);
}
public void run() {
try {
for (int i=100; i<110; i++) {
System.out.println(i);
Thread.sleep(10);
}
} catch (InterruptedException e) {
System.out.println(t + " interruped.");
}
}
}
public class WaitForThread {
public static void main(String[] args) {
AThread t1 = new AThread();
BThread t2 = new BThread();
t1.t.start();
t1.halt(t2.t); //wait for the 100-109 thread to finish
t2.t.start();
}
}
You call join on the thread before it has started. That doesn't work; in that case, join will return immediately, it's not going to wait until the other thread has started and stopped later. You can see this in the API documentation:
Thread.join()
This implementation uses a loop of this.wait calls conditioned on this.isAlive.
Thread.isAlive()
Tests if this thread is alive. A thread is alive if it has been started and has not yet died.
Reorder the statements in your main method
t1.t.start();
t2.t.start();
t1.halt(t2.t); //wait for the 100-109 thread to finish
edit to answer your questions in the comments:
If you want the thread in AThread to wait for the thread in BThread to finish before doing its job, then you'll need to call join in AThread.run, and change your main method:
class AThread implements Runnable {
Thread t;
Thread threadToWaitFor;
AThread(Thread threadToWaitFor) {
t = new Thread(this);
this.threadToWaitFor = threadToWaitFor;
}
public void run() {
// First wait for the other thread to finish
threadToWaitFor.join();
// ...
}
// ...
}
public class WaitForThread {
public static void main(String[] args) {
BThread t2 = new BThread();
AThread t1 = new AThread(t2.t);
t2.t.start();
t1.t.start();
}
}
In the Java tutorial it says about try { ... } finally { ... }:
Note: If the JVM exits while the try or catch code is being executed,
then the finally block may not execute. Likewise, if the thread
executing the try or catch code is interrupted or killed, the finally
block may not execute even though the application as a whole
continues.
Is it true that a thread can be interrupted or killed (I thought that was impossible?) such that the finally block will not be executed while the JVM running this thread is not exited/killed? (I am puzzled because the quote above is pretty explicit about this, not much room for misunderstanding.)
Edit: Broke the question down to its core intend.
Well, I stand corrected. It is possible by using deprecated methods:
#Test
public void testThread() throws Exception {
Thread thread = new Thread(new MyRunnable());
thread.start();
Thread.sleep(100);
thread.suspend();
Thread.sleep(2000);
}
class MyRunnable implements Runnable {
#Override
public void run() {
System.out.println("Start");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("Done");
}
}
}
Due to the pausing which will (most likely) occure while the thread is asleep, the finally block will never be executed.
Rafael, I believe this is one of the edge cases you are after. If a thread is blocked on something native (eg reading from STDIN or a Socket), and the JVM is in a state of shutdown, and the thread is interrupted, then finally may not be invoked.
The following example indicates this without invoking deprecated methods:
Sleep - finally is invoked.
SystemIn - finally is not invoked.
The example is very contrived, and is purely provided for demonstrative purposes :)
public class Interrupted {
static final List<Thread> THREADS = Arrays.asList(
new Thread(new Sleep()),
new Thread(new SystemIn())
);
static final CountDownLatch LATCH = new CountDownLatch(THREADS.size());
public static void main(String[] args) throws Exception {
Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook()));
for (Thread thread : THREADS) {
thread.start();
}
System.out.println("[main] Waiting for threads to start...");
LATCH.await();
System.out.println("[main] All started, time to exit");
System.exit(0);
}
static abstract class BlockingTask implements Runnable {
#Override
public void run() {
final String name = getClass().getSimpleName();
try {
LATCH.countDown();
System.out.printf("[%s] is about to block...%n",name);
blockingTask();
} catch (Throwable e) {
System.out.printf("[%s] ", name);
e.printStackTrace(System.out);
} finally {
System.out.printf("[%s] finally%n", name);
}
}
abstract void blockingTask() throws Throwable;
}
static class Sleep extends BlockingTask {
#Override
void blockingTask() throws Throwable {
Thread.sleep(60 * 60 * 1000); // 1 hour
}
}
static class SystemIn extends BlockingTask {
#Override
void blockingTask() throws Throwable {
System.in.read();
}
}
static class ShutdownHook implements Runnable {
#Override
public void run() {
System.out.println("[shutdown-hook] About to interrupt blocking tasks...");
for (Thread thread : THREADS) {
thread.interrupt();
}
System.out.println("[shutdown-hook] Interrupted");
try {
for (int i=0; i<10; i++) {
Thread.sleep(50L);
System.out.println("[shutdown-hook] Still exiting...");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}