Thread.sleep() 是否停止调用线程 运行 方法?

Does Thread.sleep() stops calling threads run method?

有人可以向我解释我遗漏了什么吗:当我调用 Thread.sleep(1000) 时,我想两个线程都应该在 1s 内执行,所以在那之后为什么我应该让 doSlice false 停止线程1秒 为什么 Thread.sleep() 不能在 1 秒内阻止他们。我的意思是在 1s 运行 方法之后甚至不应该调用来检查 while condition:

public class ExecutionScheduling  extends Thread{
    public int slice_count=0;
    public boolean doSlice=true;
    public String name;

    public ExecutionScheduling(String name){
        this.name=name;
    }

    public void run() {
        while (doSlice) {
            slice_count++;
            System.out.println(name);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutionScheduling executionScheduling=new ExecutionScheduling("ex");
        ExecutionScheduling executionScheduling1=new ExecutionScheduling("ex1");

        executionScheduling.start();
        executionScheduling1.start();

        Thread.sleep(1000);
        executionScheduling.doSlice=false;
        executionScheduling1.doSlice=false;

        System.out.println("ex: "+executionScheduling.slice_count);
        System.out.println("ex1: "+executionScheduling1.slice_count);
    }
}

Can someone please explain to me what I am missing

您缺少的是线程之间的 memory synchronization。当您启动 2 个后台线程时,它们有自己的本地内存(在它们自己的 CPU 上),您需要专门更新它们之间的任何共享数据。

使代码复杂化的是 System.out.println(...) 是一种同步方法,因此它“免费”为您提供了一些内存同步,但您不应该依赖它(见下文)。这意味着如果您删除了该调试代码,您的程序将表现不同。请注意线程代码中 System.out.print* 的任何用法。

Thread.sleep(1000);

当你运行这个睡眠命令时,它会导致主线程进入睡眠状态,但2个后台线程继续运行。他们每个人都在更新自己的 slice_count 副本,但不能保证主线程会看到这些更新。

// need to add the volatile keyword here
private volatile int slice_count;

通过将 volatile Java keyword 添加到 slice_count,这会将字段标记为由多个线程访问。当主线程访问slice_count时,它会读取它的最新值。您可能还想查看 AtomicInteger 包装 volatile int 但允许多个线程执行 incrementAndGet().

之类的事情

您遇到内存同步问题的另一个地方是:

executionScheduling.doSlice = false;
executionScheduling1.doSlice = false;

所以doSlice字段也需要是volatile:

// need to add the volatile keyword here
public volatile boolean doSlice = true;

最后,不分先后:

  • 如果可能的话,您的字段应该是 private

  • 应该是executionScheduling1executionScheduling2.

  • 定义 RunnableThread 更好。参见:

  • 您可以考虑做一个 join() 等待或每个线程完成它们的工作,然后再打印出它们的结果。

    // set the doSlices to false
    executionScheduling.join()
    executionScheduling1.join()
    // printf results
    

    如果您添加 join() 调用,那么这将根据 slice_count 为您处理内存同步,因此只要您访问它们就不再需要 volatile join() 调用完成后。是的,这令人困惑。线程编码非常重要。您仍然需要 doSlice 字段为 volatile,因为它们在 join() 完成之前被访问。