Thread.isInterrupted always returns false

2019-09-19 01:27发布

问题:

Maybe, it is a duplicate question of Thread.isInterrupted doesn't work, Thread.interrupted does. But since I use a quite different way to call Thread.isInterrupted() and have upgraded to a newer jdk, I just think this may be caused another kind of problem.

There are three threads (not including the main thread) in my program.

  • a sleep thread sleeps for 10 seconds;
  • a checker thread checks if the sleep is interrupted by another thread;
  • an interrupter interrupts the sleep thread as long as it's started.

And here is my program:

package foobar;

public class Foobar {

    public static void main(String[] args) throws Exception {
        Thread sleep = new Thread(new Sleep());
        sleep.start();

        Thread checker = new Thread(new InterruptedChecker(sleep));
        checker.start();

        Thread interrupter = new Thread(new Interrupter(sleep));
        interrupter.start();
    }
}

class InterruptedChecker implements Runnable {

    private final Thread thread;

    InterruptedChecker(Thread thread) {
        this.thread = thread;
    }

    @Override
    public void run() {
        while (true) {
            if (thread.isInterrupted()) {
                break;
            }
        }
        System.out.println("The thread is interrupted.");
    }
}

class Sleep implements Runnable {

    @Override
    public void run() {
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

class Interrupter implements Runnable {

    private final Thread thread;

    Interrupter(Thread thread) {
        this.thread = thread;
    }

    @Override
    public void run() {
        System.out.println("interrupting...");
        thread.interrupt();
    }
}

The interesting thing is that somethings (quite a lot) the program keeps running and doesn't print the message "The thread is interrupted." which means that the sleep.isInterrupted() returns false, but somethings it does.

Here is the java -version of my pc (Ubuntu 13.10 64bit):

java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

After I read Thread.isInterrupted doesn't work, Thread.interrupted does above, I tried to compile my code in a different machine using an older jdk and it worked.

And, here is the java -version of the machine (Red Hat Enterprise Linux AS release 4 (Nahant Update 3) 64bit):

java version "1.6.0_06"
Java(TM) SE Runtime Environment (build 1.6.0_06-b02)
Java HotSpot(TM) 64-Bit Server VM (build 10.0-b22, mixed mode)

So my question is that:

  1. Is there something wrong in my program?
  2. If it doesn't, does the multicore cpu or the 64 bit system have something to do with this problem?

EDIT

Thanks for Peter's comment.

What problem are you trying to solve?

I just read the post as I have stated in my comment, where in the Chapter of "Don't swallow interrupts" it says that,

code higher up on the call stack can learn of the interruption and respond to it if it wants to.

So I'm not sure if the checker thread in my program acts as, what it is called here, code higher up. I just have a try to prove the post is right. But it seems that there is something wrong.

回答1:

The interrupted flag is reset as soon as it is triggered. i.e. once sleep() have been interrupted, the flag is reset to false.


EDIT

So I'm not sure if the checker thread in my program acts as, what it is called here, code higher up. I just have a try to prove the post is right. But it seems that there is something wrong.

IMHO there is nothing higher up about another thread. What you generally have in mind is something like this.

public static void main(String... ignored) throws InterruptedException, ExecutionException {
    ExecutorService es = Executors.newSingleThreadExecutor();
    Future<?> future = es.submit(new Runnable() {
        @Override
        public void run() {
            methodA();
        }
    });
    Thread.sleep(1000);
    future.cancel(true); // interrupts task.
    long start = System.nanoTime();
    try {
        future.get();
    } catch (CancellationException expected) {
        // ignored
    }
    es.shutdown();
    es.awaitTermination(1, TimeUnit.MINUTES);
    long time = System.nanoTime() - start;
    System.out.printf("Time to cancel/shutdown was %.1f milli-seconds%n",
            time / 1e6);
}

private static void methodA() { // doesn't throw any checked exception
    for (int i = 0; i < 100; i++)
        methodB();
}

private static void methodB() {
    boolean conditionWhichIsTrue = true;
    if (conditionWhichIsTrue)
        try {
            Thread.sleep(500);
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
        }
}

prints

Time to cancel/shutdown was 1.7 milli-seconds

however, if you swallow the interrupt by commenting out the Thread.currentThread().interrupt(); line this takes about 50 seconds to stop because you only interrupted one call to sleep.



回答2:

This question also bothered me for some time. After some investigation I got the answer.

When InterruptedChecker checks isInterrupted state, the Sleep thread already died. Try to add some time consuming code after Thread.currentThread().interrupt(); in Sleep class and try again.

'interrupted' status of a thread is cleared when that thread dies.