2017-02-10 137 views
1

我對同步塊有一些懷疑。 在我的問題之前,我想分享來自其他相關職位Link for Answer to related question的答案。我從同一個答案引用Peter Lawrey如果我們正在同步讀取,我們是否需要同步寫入?

  1. 同步,確保您擁有的數據的一致視圖。這意味着您將讀取最新值,而其他緩存將獲得最新值 。高速緩存足夠聰明,可以通過 特殊總線(不是JLS所要求的但允許)相互通信。總線意味着它不必觸碰主存以獲得一致的視圖。

  2. 如果您只使用同步,您將不需要易失性。如果你有一個非常簡單的操作,同步的 會過度揮發,揮發性是有用的。

在參照上述我有以下三個問題:

Q1。假設在一個多線程應用程序中,只有一個對象或一個原始實例字段只能在一個同步塊中讀取(寫入操作可能會發生在沒有同步的其他方法中)。同步塊也在其他對象上定義。 是否聲明它是不穩定的(即使它只在同步塊內讀取)有意義? Q2302。 我瞭解同步已完成的對象的狀態值是一致的。我不確定其他對象和原始字段在Synchronized塊的讀取狀態。 假設在沒有獲得鎖的情況下進行更改,但通過獲取鎖來完成讀取。 Alwaysized塊中的所有對象和所有原始字段的值的狀態都始終具有一致的視圖。

Q3。 [更新]無論我們鎖定什麼內容,是否將從主內存中讀取正在同步塊中讀取的所有字段? [由CKing回答]

我有一個參考編碼,用於解決上述問題。

public class Test { 
    private SomeClass someObj; 
    private boolean isSomeFlag; 
    private Object lock = new Object(); 
    public SomeClass getObject() { 
     return someObj; 
    } 
    public void setObject(SomeClass someObj) { 
     this.someObj = someObj; 
    } 
    public void executeSomeProcess(){ 
     //some process... 
    } 
    // synchronized block is on a private someObj lock. 
    // inside the lock method does the value of isSomeFlag and state of someObj remain consistent? 

    public void someMethod(){ 
     synchronized (lock) { 
       while(isSomeFlag){ 
        executeSomeProcess(); 
       } 
       if(someObj.isLogicToBePerformed()){ 
        someObj.performSomeLogic(); 
       } 
     } 
    } 
    // this is method without synchronization. 
    public void setSomeFlag(boolean isSomeFlag) { 
     this.isSomeFlag = isSomeFlag; 
    } 
} 
+1

我想對此很好,但那是其中一個最誠實的工作方式。如果你在談論JMM時想到的是「從內存中獲取」的東西,那麼你還沒有明白它,應該遠離併發。但是沒有給出的代碼是不正確的。 – Voo

+0

使'isSomeFlag'揮發性將解決此問題 – ControlAltDel

+0

@Voo我編輯了我的問題,抱歉使用單詞記憶,我的意思是一致的.. –

回答

2

您需要了解的第一件事情是,在鏈接答案中討論的場景與您正在談論的場景之間存在細微的差異。你談到修改一個沒有同步的值,而所有的值都是在鏈接的答案的同步上下文中修改的。有了這個理解,讓我們來解答你的問題:

Q1。假設在一個多線程應用程序中,只有一個對象或一個原始實例字段只能在一個同步塊中讀取(寫入操作可能會發生在沒有同步的其他方法中)。同步塊也在其他對象上定義。是否聲明它是不穩定的(即使它只在同步塊內讀取)是否有意義?

是的,它宣佈字段爲volatile是有意義的。由於寫入不在​​上下文中,因此不能保證寫入線程將新刷新的值刷新到主內存。閱讀線程可能仍會因此而看到不一致的值。

假設在沒有獲得鎖的情況下進行更改,但通過獲取鎖來完成讀取。 Alwaysized塊中的所有對象和所有原始字段的值的狀態都始終具有一致的視圖。 ?

答案仍然沒有。推理與上述相同。

底線:修改同步上下文之外的值不會確保將這些值刷新到主內存。 (因爲讀寫器線程可能在寫入器線程之前進入同步塊)在​​上下文中讀取這些值的線程仍可能最終讀取較舊的值,即使它們從主內存中獲取這些值。


注意,關於原語這個問題的談判,因此同樣重要的是要明白,Java提供外的薄空中安全 32位原語(除了長和雙所有原始數據),這意味着您可以放心,您至少會看到有效的價值(如果不一致)。

+0

好吧,但鏈接的答案呢,它說:1.同步確保你有一個一致的數據視圖。這意味着您將讀取最新值,其他緩存將獲得最新值。和2.如果你只使用synchronized,你不需要volatile。如果你有一個非常簡單的操作,同步會過度,揮發性是有用的。他們是不是不正確或完整? –

+1

關聯答案中討論的場景與您正在談論的場景之間存在細微的差異。你談到修改一個沒有同步的值,而所有的值都是在鏈接的答案的同步上下文中修改的。在同步上下文之外修改值不會確保它們被刷新到主內存。 – CKing

+0

okk ..有幫助 –

1

全部​​確實是捕獲它的同步對象的鎖。如果鎖已被捕獲,它將等待其釋放。它並不以任何方式斷言該對象的內部字段不會改變。爲此,有volatile

+0

感謝您的回覆,我錯誤地使用主內存,我已編輯的問題.. –

1

當你的對象監視器A上同步,可以保證在同一個顯示器A在另一個線程同步之後會看到第一線作出任何對象任何變化。這就是​​所提供的可視性保證,僅此而已。

A volatile不管任何同步塊,變量保證可見性(僅用於變量,易失性HashMap並不意味着映射的內容將可見)。

+0

感謝您的答案。如果假設同步已經在'ObjectA'的監視器上完成,並且我們讀取同步塊內部的'ObjectB'狀態(由某個線程修改其他方法),它是否一致? –

+1

除非在'synchronized(ObjectA)'塊中對'ObjectB'進行了修改。相同的顯示器 - >更改可見。不同的顯示器 - >不能保證。 – Kayaman

+0

很好..其實這是非常接近我想知道的東西。只是爲了讓我自己清楚一個問題:如果在同一臺顯示器上進行更改,則所有字段(而不僅僅是同步完成的對象)的更改都是可見的? –

相關問題