Java while-loop 没有按预期循环

Java while-loop not looping as expected

问题

以下 while 循环不检查“正在停止”是否为真:

while (jobs.isEmpty()) {
   if (stopping) {
      running = false;
      break;
   }
}

但是,如果我在 if 语句之前插入任何其他语句,则 if 语句会可靠地进行检查,如以下循环所示:

while (jobs.isEmpty()) {
   try {
      Thread.sleep(1000);
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
   if (stopping) {
      running = false;
      break;
   }
}

当然,我希望它在没有 1 秒延迟的情况下工作,有什么解决办法,或者为什么它一开始就不起作用?


澄清

为了澄清这一点,我创建了一个简单的测试 Class:

public class Test {
    static boolean stopping = false;
    static boolean running = true;

    public static void main(String[] args) throws InterruptedException {

        new Thread(() -> {
            while (true) {
                if (stopping) {
                    running = false;
                    break;
                }
            }
            System.out.println("1. Worked");
        }).start();

        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (stopping) {
                    running = false;
                    break;
                }
            }
            System.out.println("2. Worked");
        }).start();

        Thread.sleep(1000);

        stopping = true;

        Thread.sleep(5000);
        System.exit(0);
    }
}

输出:

2. Worked

Process finished with exit code 0

最直接的问题是对标志的更新在线程中不可见,使标志可变可以解决这个问题。但是,有一种更好的方法来指示您的线程退出。

下面是一个使用 Thread 的中断方法的例子:

public class Test {

    public static void main(String[] args) throws InterruptedException {

        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    System.out.println("worker is sleeping");
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    // flag is cleared when exception is thrown,
                    //  and needs to be set again
                    Thread.currentThread().interrupt();
                }                
            }
            System.out.println("worker terminating");
        });
        t.start();
        System.out.println("main thread sleeping");
        Thread.sleep(1000);
        System.out.println("main thread interrupts worker and waits for it to finish");
        t.interrupt();
        t.join();
    }
}

使用中断的好处是像 sleep 和 wait 这样的东西知道检查标志并可以对其做出反应(例如通过早起),这是他们不能用你的 volatile 标志做的。

运行 你的例子你可以看到你必须等待工作人员完成睡眠才能检查你的标志并发现它需要退出。 运行 这个例子你可以看到,即使 worker 一次睡眠 10 秒,它也会快速退出以响应中断。