2

请先看这个片段:

public static void main(String[] args) throws InterruptedException {
    Thread anotherThread = new Thread(() -> {
        Integer countB = 0;
        while (true) {
            try {
                System.out.println("B count: " + ++countB);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    anotherThread.start();

    Integer countA = 0;
    while (true) {
        System.out.println("A count: " + ++countA);
        Thread.sleep(1000);
    }
}

这按预期工作。我看到 countA 大约是 countB 的 2 倍。

现在我在外部 while 循环中添加一行:

public static void main(String[] args) throws InterruptedException {
    Thread anotherThread = new Thread(() -> {
        Integer countB = 0;
        while (true) {
            try {
                System.out.println("B count: " + ++countB);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    anotherThread.start();

    Integer countA = 0;
    while (true) {
        anotherThread.interrupt();
        System.out.println("A count: " + ++countA);
        Thread.sleep(1000);
    }
}

主线程中断另一个线程。在我这样做之后,countA 不再是 2x countB。他们现在总是相差一个。

为什么这样?睡眠/中断如何工作?

4

4 回答 4

3

基本上调用interrupt将从它的调用中唤醒线程sleep。通常你会中断一个线程,因为你希望它优雅地结束......但在这种情况下它只是被唤醒,然后继续在它的无限循环中运行。

查看文档以获取更多信息: https ://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html

于 2015-12-02T07:26:05.360 回答
0

这是对Buddy 答案的补充,这是正确的。

在第一种情况下,您有

B    A
.    .
.    A
.    .
B    A
.    .
.    A
.    .
B    A

但随着中断它变为:

B    A (interrupts B, B continues in loop)
B    .
.    A (interrupts B again)
B    .
.    A
B    .
.    A
B    .
.    A

导致B不等待2秒......

于 2015-12-02T07:34:58.593 回答
0

如果您中断另一个线程,它将从睡眠中唤醒。换句话说,它不像你的主线程(countA)那样睡 2 秒,但只有 1 秒。

中断的作用:它唤醒处于睡眠状态的线程。当调用interrupt()时,方法 sleep(int) 将抛出InterrruptedException以指示时间未过去。

于 2015-12-02T07:40:21.257 回答
0

中断需要被中断的线程进行合作,它必须寻找它被中断的迹象并处理它们。如果您将 anotherThread 更改为此:

Thread anotherThread = new Thread(() -> {
    Integer countB = 0;
    while (!Thread.currentThread().isInterrupted()) {
        try {
            System.out.println("B count: " + ++countB);
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
    }
});

然后中断线程将导致它完成。

调用中断设置中断标志,当线程处于睡眠状态并检测到该标志被设置时,sleep 方法会抛出一个 InterruptedException ,同时清除线程上的中断标志。为了恢复标志值,需要在 catch 块中的线程上调用中断。然后让 while 循环测试检查中断标志,使线程有机会退出。

于 2015-12-02T15:30:03.537 回答