簡體   English   中英

為什么一旦線程啟動,它就永遠不能在java中再次啟動

[英]Why Once a thread has been started, it can never be started again in java

我知道“一旦線程啟動,就永遠無法重新啟動”。
但我想知道為什么?
如果允許在其他時間再次啟動,那有什么不對?
為什么,唯一可以啟動線程的時候是它處於NEW狀態? 為什么至少在DEAD之后也不能呢?

public class ThreadDemo {

    public static void main(String[] args) {

        Thread thread = new Thread(new MyRunnable());
        thread.start();
        thread.start(); // java.lang.IllegalThreadStateException

    }

}

class MyRunnable implements Runnable{

    @Override
    public void run() {

        System.out.println("run().Thread.currentThread().getName() : " + Thread.currentThread().getName());

    }
}

注意:我已經完成了這些帖子 但我的問題更加具體和具有描述性。

在這里,請注意我想知道這主要是為了理解線程內部功能以及GC等相關方面如何與線程狀態一起工作。

因為Thread實現不允許它。 您總是可以使用Runnable創建另一個Thread實例

new Thread(new MyRunnable()).start();
new Thread(new MyRunnable()).start();

編輯

JLS-17.4.3。 計划和計划訂單 (部分),

如果所有動作都以與程序順序一致的總順序(執行順序)發生,則一組動作是順序一致的,此外,變量v的每個讀取r將寫入w寫入的值看作v,使得:

 w comes before r in the execution order, and there is no other write w' such that w comes before w' and w' comes before r in the execution order. 

順序一致性是對程序執行中的可見性和排序的有力保證。 在順序一致的執行中,對於與程序的順序一致的所有單個動作(例如讀取和寫入)存在總順序,並且每個單獨的動作是原子的並且對於每個線程立即可見。

如果Thread實例可以再次啟動,那么順序一致性的實現可能是不可能的。

我可以給你點幾點。

  1. 垃圾收集:活動線程被視為垃圾收集的根。 意味着如果某個對象可以從活動線程到達那么它就不能被垃圾收集。
    現在,如果線程處於非活動狀態(死機),則任何gc算法都將確定,如果該線程只能訪問的特定對象現在符合垃圾收集條件,那么它將收集該對象。 但是現在如果你再次讓你的線程活動它是一個問題,因為它的堆棧會有一個損壞的視圖,因為許多對象可能已經被垃圾收集了。 你的整個程序都會變得混亂。

    要解決此問題,您將維護另一個狀態,讓我們將其稱為GC_COLLECTABLE。 這意味着線程處於活動狀態意味着它的狀態!= GC_COLLECTABLE。 現在問題出現了程序員設置此狀態時的廣告。 它的類似問題是無法停止線程或確定某些對象何時必須進行垃圾回收。 它本身就是一個非常復雜的問題需要解決。 解決此問題的最簡單方法是,一旦線程無效或無法重新啟動它就不會激活它。

  2. thread.join():正如Eliott建議的那樣。 假設有三個線程T1 T2和一個可重啟的線程RST。 現在假設T1和T2都調用RST.join()。 T1和T2退出連接時出現問題。 如果可以再次啟動線程,則join方法是無限的。 如果你允許join在DEAD狀態之后返回,那么有種族和未確定的行為導致T1完成join()但是T2仍然會延遲,因為RST已經重新啟動。

  3. API更改:您如何建議應該實施。

    Thread.start(); //這種方法是否足夠 可能不是

    如果我在一個循環中調用Thread.start()會發生什么 - >如果先前的線程沒有死或者將重新啟動死線程,它會創建新線程( 聽起來像Executors.newCachedThreadPools

    - >或者如果當前線程沒有死或者重新啟動線程則拋出異常不是一個非常好的方法,這會使你的程序更加不確定 因為同一個線程可能會花費不同的時間用於同一任務,因此您將無法預測程序輸出。 至少你需要從start方法對已檢查的異常進行簽名更改,或者定義一個新的方法重啟,但它會遇到與上面相同的問題。

從我的角度來看,第一點足夠單獨從重新啟動線程。 此外,您可以通過使用ThreadPools獲得類似的功能,其中線程可以重用於不同/類似的任務

如果查看線程的生命周期,則會創建該線程,然后將其移動到等待執行的線程池中

一旦完成它的工作,它就會被調度程序破壞,因此系統不再知道它(空引用) - 因此它不能再次啟動,因為Elliot建議創建一個可以完成工作的新線程是完全正常的。 MyRunnable函數,但命名線程執行的范圍是唯一的

暫無
暫無

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

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