簡體   English   中英

Thread.sleep() 是否停止調用線程運行方法?

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

有人可以向我解釋一下我錯過了什么:當我調用Thread.sleep(1000)時,我想兩個線程都應該在 1s 內執行,所以在那之后我為什么要讓doSlice false 在 1s 內停止線程,為什么Thread.sleep()只是不會在 1 秒內阻止他們。 我的意思是在 1s 之后運行方法甚至不應該被調用來檢查 while 條件:

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);
    }
}

有人可以向我解釋我錯過了什么

您缺少的是線程之間的memory 同步 當您啟動 2 個后台線程時,它們有自己的本地 memory(在它們自己的 CPU 上),您需要專門更新它們之間的任何共享數據。

使代碼復雜化的是System.out.println(...)是一種同步方法,因此它“免費”為您提供了一些 memory 同步,但您不應該依賴它(見下文)。 這意味着如果您刪除了該調試代碼,您的程序的行為將有所不同。 小心在線程代碼中使用System.out.print*

 Thread.sleep(1000);

當你運行這個 sleep 命令時,它會導致 go 的主線程休眠,但 2 個后台線程繼續運行。 他們每個人都在更新自己的slice_count副本,但不能保證主線程會看到這些更新。

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

通過將volatile Java 關鍵字添加到slice_count ,這會將字段標記為被多個線程訪問。 當主線程訪問slice_count時,它將讀取它的最新值。 您可能還想查看AtomicInteger ,它包裝了一個volatile int但允許多個線程執行諸如incrementAndGet()之類的事情。

memory 同步問題的另一個地方是:

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

所以doSlice字段也需要是volatile

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

最后,沒有順序:

  • 如果可能,您的字段應該是private的。

  • 它應該是executionScheduling1executionScheduling2

  • 定義Runnable而不是Thread是更好的模式。 請參閱: https://stackoverflow.com/a/541527/179850

  • 您可能會考慮執行join()以等待或每個線程在打印出它們的結果之前完成它們的工作。

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

    如果您添加join()調用,那么它將根據 slice_count 為您處理slice_count同步,因此只要您在join()調用完成訪問它們,它們就不再需要是volatile的。 是的,這令人困惑。 線程編碼是不平凡的。 您仍然需要doSlice字段是volatile的,因為它們是在join()完成之前訪問的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM