线程 - 睡眠和中断

Thread - Sleep and interrupt

请先看这个片段:

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。他们现在总是相差一个。

为什么会这样? sleep/interrupt 是如何工作的?

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

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

这是对 的补充,是正确的。

第一种情况你有

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 秒...

如果您中断 anotherThread 它将从睡眠中唤醒。换句话说,它不会像您的主线程 (countA) 那样休眠 2 秒,而只会休眠 1 秒。

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

中断需要被打断的线程配合,它要寻找自己被打断的迹象并进行处理。如果将 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();
        }
    }
});

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

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