4

當沒有同步塊並且沒有volatile變量時,由一個線程執行的寫入何時對不同線程可見?這裏是一個簡化的快速排序例子:創建和連接線程時的副作用的可見性

int middle = partitionForTheFirstTime(array); 

Thread t = new Thread(new Quicksorter(array, 0, middle - 1)); 
Thread u = new Thread(new Quicksorter(array, middle + 1, array.size - 1)); 

t.start() 
u.start(); 

t.join(); 
u.join(); 

(爲簡單起見,假設兩個「工作線程」不衍生任何額外的線程)

是否與兩個線程加入保證當前線程看到了所有的副作用?


與此相關的,如果我初始分區之前創建的線程會發生什麼?

Quicksorter a = new Quicksorter(); 
Quicksorter b = new Quicksorter(); 

Thread t = new Thread(a); 
Thread u = new Thread(b); 

int middle = partitionForTheFirstTime(array); 

a.setParameters(array, 0, middle - 1); 
b.setParameters(array, middle + 1, array.size - 1); 

t.start() 
u.start(); 

t.join(); 
u.join(); 

這兩個線程是否能夠看到由partitionForTheFirstTime()引起的副作用?換句話說,創建一個線程產生一個發生之前的關係,或者開始一個線程?

+0

創建一個線程對象不會創建一個線程,並且不會做太多工作。它只有當你開始()它創建一個真正的線程。 – 2011-06-07 10:41:39

回答

8

section 17.4.5 of the JLS

它遵循從上述定義:

  • 解鎖在監視器之前發生該顯示器上每個後續鎖。
  • 在每次後續讀取該字段之前,都會發生對易失性字段(第8.3.1.4節)的寫入。
  • 在啓動的線程中執行任何操作之前,會發生對線程啓動()的調用。
  • 線程中的所有操作都會在任何其他線程從該線程上的join()成功返回之前發生。
  • 任何對象的默認初始化發生在程序的任何其他操作(非默認寫入)之前。

該位約start()join()是給你的那些有關 - 換句話說,當你join() -ed一個線程成功,你會看到在該線程的所有操作。如果你線程start(),那個新線程將會看到在線程中已經發生的所有動作,這些動作調用start()

編輯:另見"memory consistency errors"

+0

我找到了完美的答案[這裏](http://download.oracle.com/javase/tutorial/essential/concurrency/memconsist.html),也許你想加入?:) – fredoverflow 2011-06-08 10:46:22

0

除非您在執行start()之前執行partitionForTheFirstTime(),否則兩個線程將對相同的數據進行操作。但是在這個例子中,通過將引用值傳遞給這些單獨的線程,您需要謹慎。數組值通過引用傳遞,與通過值傳遞的原始值相反。結果兩個線程將在同一個表上運行,這可能會導致競爭條件

+0

每個線程都對數組的一個不重疊的片段進行排序,所以它不應該是個問題,對吧? – fredoverflow 2011-06-07 11:25:45