2017-04-08 75 views
4

我想知道如果一個私人布爾字段的getter方法強制其他線程獲取最新的更新值?這是揮發性領域的替代品嗎? 例如:getter方法是Java中volatile的替代方法嗎?

Class A { 
    private boolean flag; 

    public boolean getFlag() { 
     return this.flag; 
    } 

    public void setFlag(boolean flag) { 
     this.flag = flag; 
    } 
} 

VS

Class B { 
    public volatile boolean flag; 
} 

編輯:這是真的,整個對象是由一個線程(包括私營領域)的緩存,這樣,當我打電話,吸氣它會返回緩存的私人領域?

+4

號這兩個是等效沒有辦法。你爲什麼會認爲他們是?從邏輯上講,如果'volatile'與getter相同,那麼爲什麼我們需要一個全新的語言關鍵字呢? –

+0

正如我所說,我認爲getter強制線程獲得未緩存的值。爲什麼不吸取最後一次更新的值? –

+0

也許您需要查看[JLS](http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.3.1.4)。 –

回答

3

不,吸氣不會造成現場進行同步。

談論在多線程環境下讀取和寫入原始的時候,我們有三個問題,造成CPU

  1. 原子性:它可能需要存儲或加載運行一個以上的彙編指令,例如,在32位CPU上寫入一個64位整數。當前線程可能會被操作系統在指令序列的中間置於睡眠狀態。
  2. 可見性:在一個內核上運行的線程可能無法讀取來自其他內核的其他線程寫入的最新值。只是因爲CPU這麼說。
  3. 重新排序:爲了使程序運行得更快,CPU按照它認爲合適的方式混合了彙編指令的順序。

Getter不能解決任何這些問題。即使它是,JIT編譯器可能會完全優化該功能。那又如何?

揮發性是解決上述問題的方法之一。鎖也是如此。它們確保一個線程讀取原語的最新值,或者確保寫入的值對其他線程可見。它們還會使彙編指令按照編譯的原樣運行,而不會進行任何混合。

作爲一個附註,生成的程序集可能與您在代碼中編寫的程序完全不同。你問自己:「我在我的代碼中寫道從flag中讀取,那麼爲什麼程序不能從字段本身讀取?」編譯器可以做任何它認爲合適的組件來儘可能快地組裝。通過而不是添加了任何鎖定或易失性說明符,您基本上告訴編譯器不涉及多線程訪問,並且編譯器(以及隨後的CPU)可以自由地假定該對象未被多個線程觸及。它可能是這個對象可能不是在第一個地方創建的。 JIT編譯器可能會說「好吧,將這個布爾值聲明爲一個寄存器並將其視爲整個對象」。這是非常可能的。

編輯:整個對象是否被一個線程(包括私有字段)緩存是真的,這樣當我調用getter時它會返回緩存的私有字段?

你不能這樣假設。它取決於JVM,底層操作系統和底層CPU。它可能完全緩存,部分或根本不緩存。提醒你,即使對象被高速緩存,大部分CPU的外部都有多個高速緩存行,它在哪裏被高速緩存?在寄存器或其中一個緩存行中?

+0

「_Java解決了第一個問題_」 - 請參閱[JLS 17.6](https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.6);讀取和寫入非易失性64位值不保證是原子性的。 –

+0

@BoristheSpider讓我更新我的回答 –

+0

@BoristheSpider也是,無法保證空間呢? –

0

getter強制線程獲取未緩存的值?這是揮發性領域的替代品嗎?

沒有,getter方法不強求什麼,所以你必須需要一個volatile使當前線程看到由其他線程更新的最新值,否則,你可能會看到過時的值。

您需要知道here以下的文字,並清楚地理解原子訪問的概念。

volatile變量對其他線程始終可見。這 也意味着,當一個線程讀取volatile變量,它認爲沒有 只是最新的變化揮發

+0

是不是應該得到真正價值的吸氣方法?或者是整個對象被緩存(包括私有字段),所以當我調用getter時它會返回緩存的私有字段? –

+1

@ ovidiu-miu「getter」並不是特別的。這只是一種方法,就像任何其他方法一樣。它需要參數並返回一個值。當一個變量被多個線程讀取時,這些讀取可能不一致。句號。 –

1

我想知道如果一個私人布爾字段一個getter方法迫使其他線程,以獲得最新更新值

號它不會強迫其他線程獲得在沒有最新值volatile的關鍵字。

這是一個替代揮發性領域?

號簡單的getter呼叫不是替代得到沒有volatile關鍵字boolean值的最新值。

更好的解決方案解決你的問題:使用AtomicBoolean

可以用原子方式更新的boolean值。有關原子變量屬性的描述,請參閱java.util.concurrent.atomic包規範。

很少有更多有用的鏈接:

Atomic package-summary

What is the difference between atomic/volatile/synchronized?