簡體   English   中英

為什么在Java中的線程對象上調用start()時沒有立即調用run()

[英]Why is run() not immediately called when start() called on a thread object in java

還是?
我有一個來自的線程對象:

Thread myThread = new Thread(pObject);

其中pObject是實現Runnable接口的類的對象,然后我在線程對象上調用了start方法,如下所示:

myThread.start();

現在,我的理解是,當調用start()時,JVM隱式(立即)調用了run()方法,該方法可能會被覆蓋(就我而言)

但是,在我的情況下,似乎沒有立即(按需要)調用start()方法,而是直到從調用塊完成其他語句/方法為止,即,如果在start()調用之后我有一個方法,例如:

myThread.start();
doSomethingElse();

doSomthingElse()在運行run()方法之前就已執行。
最初的前提是總是在調用start()之后立即調用run()可能使我錯了。 請幫忙! 再次希望在start()之后立即執行run()。 謝謝。

嗯... run()方法將在另一個線程中運行。 根據定義,這意味着您無法對當前線程將在其之前或之后執行的語句做任何假設,除非您明確地同步它們。

run()是新線程在代碼中執行的第一件事,但是新線程首先要進行一些設置工作,並且不能保證新線程會在原始線程之前完成任何大量工作線程繼續調用doSomethingElse()

您認為這里沒有保證是正確的。 對多線程代碼的行為進行假設是造成很多痛苦的根源,請不要這樣做!

現在,我的理解是,當調用start()時,JVM隱式(立即)調用了run()方法。

那是不對的。 它確實隱式調用run() ,但調用不一定立即發生。

現實情況是,在進行start()調用后的某個時間點,可以安排新線程使用。 實際調度取決於本機調度程序。 它可能立即發生,或者在安排子線程之前,父線程可能會持續一段時間。

為了強制您的線程立即開始運行(或更准確地說,是在doSomethingElse()之前開始運行),您需要進行一些顯式的同步。 例如這樣的事情:

    java.util.concurrent.CountDownLatch latch = new CountdownLatch(1);
    new Thread(new MyRunnable(latch)).start();
    latch.await(); // waits until released by the child thread.
    doSomethingElse();

哪里

class MyRunnable implements Runnable {
    private CountDownLatch latch;
    MyRunnable (CountDownLatch latch) { this.latch = latch; }
    public void run() {
        doSomeStuff();
        latch.countDown(); // releases the parent thread
        doSomeMoreStuff();
    }
    ...
}

還有其他方法可以使用並發類或Java的互斥/等待/通知原語1實現同步。 但是,兩個線程之間的顯式同步是保證所需行為的唯一方法。

請注意,子線程中的doSomething()調用將在釋放父線程之前完成,但是對於doSomethingElese()doSomeMoreStuff()的執行順序,我們無能為力。 (一個可以在另一個之前運行,反之亦然,或者它們可以並行運行。)


1-不建議使用wait / notify ,但是如果並發API不可用,則這可能是您唯一的選擇; 例如在Java ME上。

當您調用myThread.start() ,您的線程可用於執行。 它是否會真正獲得CPU以及持續多長時間-由OS調度程序決定。 實際上,您的run()可能會立即獲得控制權,但是在執行任何您可以注意到的操作之前將其丟失。 確保線程在doSomethingElse()之前執行所需內容的唯一方法是使用顯式同步。

您已開始一個新線程。 該線程與啟動它的線程並行運行,因此順序可以是:

pObject.run();
doSomethingElse();

要么

doSomethingElse();
pObject.run();

或更可能會有一些交叉。 pObject.run()可能在doSomethingElse()的中間運行,反之亦然,或者一個將在另一個完成之前啟動,依此類推。 了解這一點並理解原子操作的含義很重要,否則您會發現自己遇到了一些很難發現的錯誤。

如果兩個或多個線程訪問相同的變量,則更為復雜。 在某些情況下,一個線程中的值可能永遠不會更新。

我強烈建議:

  1. 除非絕對必要,否則不要使程序成為多線程。

  2. 如果您願意,請從封面開始閱讀並閱讀,以涵蓋Brian Goetz的Java Concurrency in Practice

在線程對象上調用start方法可能不會使jvm立即執行run()方法,而是使線程成為可運行的並准備執行,在這種情況下,父線程首先執行其代碼,然后將控制權傳遞給子線程線程,如果您希望子線程在執行父線程代碼之前執行,請在父線程中使用chileThreadObject.join()方法。

暫無
暫無

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

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