簡體   English   中英

用Java創建線程

[英]Creates thread in Java

我不明白,當我創建線程時,第一種情況和第二種情況會得到什么?

通常,它們之間有區別嗎?

ExecutorService executorService = Executors.newCachedThreadPool();

NewThread newThread =  new NewThread(Thread.MAX_PRIORITY);
for(int i = 0;i < 5; i++){
    executorService.execute(newThread);
}

ExecutorService executorService = Executors.newCachedThreadPool();

for(int i = 0;i < 5; i++){
    NewThread newThread =  new NewThread(Thread.MAX_PRIORITY);
    executorService.execute(newThread);
}

鑒於您提供的是,最佳答案是:在第一種情況下,您可能會遇到錯誤。 第二種方法是完全安全的(當然,假設您沒有做不安全的事情)。

我知道,幫助不大,所以讓您了解一些背景知識。

NewThread最有可能實現Runnable,因此它應具有方法void run(),如下所示:

class NewThread implements Runnable {
    void run(){
          //do something
    }
}

現在,我們不知道實際的實現是什么,但是我們仍然可以進行一些分析。 示例的整個結果取決於NewThread是有狀態的還是無狀態的。 “有狀態”表示該類的實例具有狀態,例如某些內部字段(屬性)。 “無狀態”只是“無狀態”。

如果NewThread是無狀態的,則在兩種情況下結果都是相同的-ExecutorService在新線程下執行run()方法,並且由於無論如何都沒有變量狀態,所以我們不會有任何問題。

如果NewThread是有狀態的,則在您的第一個示例中可能會出現一些問題。 編譯器在這里不會有多大幫助,因為代碼可以,但是邏輯可能被破壞了。 想象一下:

class NewThread implements Runnable {
    int x = 0;
    void run(){
          while (x<10)
               x = x + 1;
    }
}

您在這里看到的是種族狀況的手冊示例。 比我強的作者比我更好地解釋了這個問題,所以我只提供一些閱讀鏈接,例如thisthisthis (當然:也可以使用Google)。 基本上,這種情況下的競爭條件是,當我們執行x = x + 1時,我們首先需要讀取x,然后對其進行寫入。 在讀取和寫入之間,其他一些線程可能已經修改了x的值,而該值可能會被該線程覆蓋。

在某些情況下,NewThread是有狀態的,但仍然可以正常工作。 如果您通過同步關鍵字(例如,參見上面的第3個鏈接)或使用同步數據結構來手動同步代碼,則會發生這種情況:

class NewThread implements Runnable {
    AtomicInteger x = new AtomicInteger(0);
    void run(){
          while (x<10)
               x.incrementAndGet(); //getAndIncrement would work too - we don't care about the result, only about incrementing
    }
}

“原子”是指對該類的每個操作都被視為單個步驟,例如讀或寫(而x = x + 1是兩個步驟,這正是導致競爭狀態的原因)。 JDK中已經有幾個可用的原子類。 如果您想自己實現類似的功能,則可能要使用synced關鍵字或某些類似鎖的對象來保護變量。

在第一種情況下,您將創建一個線程實例並嘗試執行5次,在第二種情況下,您將創建5個不同的線程實例並嘗試執行它們。 這是否回答你的問題?

認為您的問題源於命名錯誤。 你在做

executorService.execute(newThread);

可能您現在想知道為什么該服務(基於線程池)如何處理Threads

簡單的答案:不是。 該接口Executor.execute()接受一個Runnable對象。

換句話說:你的代碼將調用run方法, 你的NewThread提供。

當然,您的問題的“直接”答案是:在第一種情況下,您將5次相同的 Runnable發送給執行者; 而在第二種情況下,您將向執行程序發送5個不同的 Runnable。

在意義上不同:不同的對象-由於它們屬於同一類,因此對於兩個示例都應該發生相同的事情。 除非您在NewThread中進行一些令人討厭的靜態操作,否則, 考慮到您對問題的總體印象,這也就不足為奇了。

我沒有嘗試過,但是第一種情況應該執行一次,然后開始拋出異常。 一旦Thread實例終止,嘗試再次啟動它是非法的。 請參閱javadoc以獲取開始信息

IllegalThreadStateException-如果線程已經啟動。

您的第二個示例在這兩個示例中更為明智,因為它創建了5個單獨的Thread實例。

暫無
暫無

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

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