2014-10-06 74 views
1

我無法在任何地方找到這個特定場景。同步訪問非易失性字段線程安全嗎?

如果我從兩個線程同時呼叫init(),其中一個呼叫是否保證看到time不再爲空? time是否也需要volatile

它是否像join()這是一個同步點?

private Long time; 

synchronized void init() { 
    if (time != null) { 
     throw new IllegalStateException("Already initialised."); 
    } 

    this.time = System.currentTimeMillis(); 
} 
+0

我認爲如果變量是非易失性的,那麼在多個處理單元上可能會出現緩存問題。 – 2014-10-06 05:35:16

+2

如果這不是線程安全的,'synchronized'將完全無用。 – Mat 2014-10-06 05:36:40

+0

*同步*關鍵字隱式暗示a *發生在*關係之前。所以,是的,它是線程安全的。 – TheLostMind 2014-10-06 05:37:31

回答

3

當一個線程進入該​​方法,它獲取一個implicit鎖在例如,它執行到實例的state的變化是將其他線程可見,等待進入同步方法。

當一個同步方法退出時,它自動地建立一個 之前發生的關係具有用於相同對象的 同步方法的任何後續調用。 這保證對所有線程都可見對象狀態的更改 。

文檔中的最後一行提到它很清楚。這個國家是volatile還是non-volatile並不重要。

+0

如果不是「同步」方法,而是將語句包裝在「synchronized(lockObject)」塊中?現在我正在改變鎖對象以外的其他對象的狀態。 – Monstieur 2014-10-06 05:48:06

+0

是的,在這種情況下,它不能得到保證。然後你可以使用volatile關鍵字。 – BatScream 2014-10-06 05:50:39

+4

您正在從其上下文中提取報價。擁有一個同步塊不會保證所有**線程都可以看到這些更改,只有這些線程*隨後使用一個同步塊獲取同一監視器。該引用僅在您從http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html取消引用的頁面上的示例類「SynchronizedCounter」的上下文中有效(不是您需要引用從哪裏引用) – 2014-10-06 05:55:13

0

更簡單的解決方案是使用靜態類初始化程序。

class TimeHolder { 
     public static final long time = System.currentTimeMillis(); 
} 

假定您是初次使用該類時還是創建對象時啓動。

+0

這只是一個例子。我需要線程安全的東西。 – Monstieur 2014-10-06 06:23:44

+0

問題越真實,答案越貼切。 – 2014-10-06 06:37:09