2011-11-16 31 views
2

如果使用ThreadPoolExecutor執行Runnable,並且如果此Runnable修改某個共享狀態,是否可以保證在原始線程中這些共享狀態的更改是否可見提交可運行池到池?假設只有1位作者共享狀態和1位讀者。我知道,當您使用ExecutorService返回Future時,執行Future.get()將保證可見性。使用ThreadPoolExecutor.execute()執行內存可見性保證


class State { 
    private int x; 
    public State(int y) { x = y; } 
    public void setX(int y) { x = y; } 
    public int getX() { return x; } 
} 

main() { 
    threadPool = new ThreadPoolExecutor(8, 16, 100, TimeUnit.SECONDS, new ArrayBlockingQueue(...)) 

    final State myState = new State(1); 

    threadPool.execute(new Runnable() { 
     public void run() { 
      myState.setX(50); 
     } 
    }); 

    while (true) { 
     if (myState.getX() == 50) { 
      break; 
     } 
     sleep(); 
    } // would this loop terminate? 
} 

回答

5

這要看,有沒有隱含保證狀態的變化會立即反映在原來的線程,這主要是因爲原來的線程可能不會被當更新的x值的緩存副本另一個線程更改主存儲器中的值x

您可以解決此通過使用volatile關鍵字添加一個明確的保證,如:

class State { 
    private volatile int x; 
    public State(int y) { x = y; } 
    public void setX(int y) { x = y; } 
    public int getX() { return x; } 
} 

這告訴它不能緩存的x值編譯器,而且每次程序讀取x它必須檢查主內存中的值。一旦其他線程修改它,這將使原始線程立即看到新值x

更多細節在這裏:

http://www.javamex.com/tutorials/synchronization_volatile.shtml

1

幾乎任何理智的方法來檢測該線程已完成其工作(比volatile其他只同步一個變量)也將保證內存的同步視圖。你的例子無法確定線程已經完成,所以它顯然不起作用。 C#不提供任何特定的及時性保證,因此不能使用sleep作爲同步的一種形式。

+0

謝謝 - 這對我有意義。我上面的例子實際上有點做作。我看到的原始代碼實際上啓動了一大堆針對線程池的異步任務。這些任務可能會更新某些狀態。主線程只是在一個緊密的循環中輪詢狀態並做一些工作。它不必顯式等待任務完成。我將編輯我的代碼示例以反映此情況。 – Harish

+0

如果您通過某種理智的線程間信號設備(如事件)輪詢狀態,則信號設備可能保證,如果線程X看到線程Y的事件/信號,它還會看到線程X在發送之前發生的任何內存更改信號或事件。只是不要假裝它 - 使用正確的信號/同步設備。 –