2012-05-22 54 views
1

如果我有一個實現了java.lang.Runnable的類,在技術上沒有任何東西阻止多個線程同時調用run相同的實例Runnable。例如:Runnable的實現是否允許併發調用在同一個實例上運行()?

Runnable r = new MyRunnable(); 

//start thread 1 
new Thread(r).start(); 

//start thread 2 
new Thread(r).start(); 

這是不是一個真正的問題,如果run方法完全是「自足」(即不依賴於任何私有實例成員),因爲沒有線程之間共享的變量,所以你Runnable永遠不會得到「損壞」的內部狀態。但我認爲在大多數情況下,您的Runnable有一些私人實例成員,它操縱run,那麼該怎麼辦?

要使用示例,我的MyRunnable類有一個私人mode字段。主要目的是乾淨地停止run方法(將mode設置爲STOPPED),但它也有其他用途。

public static class MyRunnable implements Runnable 
{ 
    enum Mode { RUNNING, PAUSED, STOPPED, FASTFORWARDING, REWINDING; } 

    private volatile Mode mode; 

    @Override 
    public void run() 
    { 
     mode = Mode.RUNNING; 
     while (mode != Mode.STOPPED) 
     { 
      //do stuff. possibly other changes to the mode. 
     } 
    } 

    public void setMode(Mode mode) 
    { 
     this.mode = mode; 
    } 

    public Mode getMode() 
    { 
     return mode; 
    } 
} 

正如你可以看到,如果我同時執行多個線程的MyRunnable相同情況下(如前所示),任何改變mode會以不同方式影響同時運行的線程。例如,如果一個線程將mode設置爲STOPPED,另一個線程可能會在每個其他線程看到它被設置爲STOPPED之前將mode更改爲其他值。這很容易阻止線程退出while循環。

那麼我如何設計一個Runnable爲「可同時使用」?它甚至有可能嗎?這不值得嗎?有沒有像C#的ThreadStatic屬性我可以使用(我認爲這將是完美的在這種情況下)?

回答

9

這是更爲常見的構建你MyRunnable的多個實例,在這種情況下,而不是保護他們免受多種用途:

//start thread 1 
new Thread(new MyRunnable()).start(); 
//start thread 2 
new Thread(new MyRunnable()).start(); 

具有多線程工作的全部目的是爲了達到良好的並行計算。如果線程需要鎖定公共資源(比如工作隊列等),那麼很好,但是編寫Runnable以使它們「同時可用」不應該是理所當然的 - 應該有充足的理由這樣做。

這是可能的嗎?

當然有可能。線程在它們之間的所有時間共享資源。但是,對於您的變量Mode mode,應該使用Runnable類的多個實例完成此操作。

如果多個線程在呼喚公共代碼,一個模式,你可以考慮使用ThreadLocal存儲每個線程的信息。但是,你MyRunnable的多個實例的存儲裏面領域會比具有存儲在ThreadLocalmode一個MyRunnable實例更有效。

這難道不值得嗎?

肯定是不是如果這是在原則上完成的話值得。同樣,分支線程的重點是讓它們儘可能地與其他線程分離以利用多個處理器。

0

一般來說,這是不值得的。

無論如何,創建Runnable的新實例的成本不能太高。如果是這樣,你必須看看如何分解那些初始化成本很高的部分,並確保它們是線程安全的。

你當然也可以使用ThreadLocal變量,它總的來說非常有用,但可能不是這種情況。

1

與設計任何其他方法或類的線程安全方式相同。 Runnable沒有任何內在的不同。

C#ThreadStatic相當於ThreadLocalVariable,但是否這是適當的解決方案是任何人的猜測,因爲我們無法知道您希望您遵循什麼行爲。

如果你想有效地讓每個線程運行有你的Runnable的獨立執行(與問候國家)會更有意義(和簡單得多)有不同的實例。

0

嗯,我不能說我在Java中有很多使用MP的經驗,所以我不會去討論常見的用法,但是在閱讀RunnableThread文檔之後,聽起來像Runnable打算成爲正是名字所暗示的:一個可運行的對象。具體來說,文檔提到在不希望實現Thread的情況下使用Runnable,但希望使用類似的概念。我其實認爲這使得Runnable成爲封裝並行或併發算法的類的理想選擇。當然,沒有什麼可以暗示你不應該或不能專門爲併發設計Runnable。當然,這本身(取決於任務)不僅僅是一個SO問題可以解決的問題。

編輯:我應該澄清一下,我提到在Runnable中封裝了並行或併發算法,但我的意思是要傳達一下,將任務封裝在Runnable中也是有意義的,然後讓調用者確定是否分配並行例如,通過在併發線程中調用該任務的資源。我的觀點就是,正如文檔所暗示的,如果你能想象一個對象正在運行(在任何情況下),那麼Runnable可能是一個不錯的選擇!

0

我覺得OP的問題是,在某些情況下,當了Runnable是資源重,有沒有辦法來避免重新創建這些的Runnable?

我的經驗是,你總是可以創建簡單的Runnable指重物資源(如巨大的陣列等)。避免在多個線程上調用相同的Runnables,但爲每個線程創建不同的Runnable在我看來是更好的做法。

相關問題