亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

什么時候在Java中使用volatile關鍵字?

什么時候在Java中使用volatile關鍵字?

達令說 2019-08-26 17:32:02
什么時候在Java中使用volatile關鍵字?我讀過“ 什么時候在Java中使用'volatile'? ”但我仍然感到困惑。我怎么知道何時應該標記變量volatile?如果我弄錯了,要么在需要它的東西上省略volatile,要么在不需要的東西上放置volatile呢?在確定多線程代碼中哪些變量應該是易變的時,有哪些經驗法則?
查看完整描述

3 回答

?
小怪獸愛吃肉

TA貢獻1852條經驗 獲得超1個贊

當你想讓一個成員變量被多個線程訪問但不需要復合原子性(不確定這是否是正確的術語)時,你基本上使用它。

class BadExample {
    private volatile int counter;

    public void hit(){
        /* This operation is in fact two operations:
         * 1) int tmp = this.counter;
         * 2) this.counter = tmp + 1;
         * and is thus broken (counter becomes fewer
         * than the accurate amount).
         */
        counter++;
    }}

以上是一個不好的例子,因為你需要復合原子性。

 class BadExampleFixed {
    private int counter;

    public synchronized void hit(){
        /*
         * Only one thread performs action (1), (2) at a time
         * "atomically", in the sense that other threads can not 
         * observe the intermediate state between (1) and (2).
         * Therefore, the counter will be accurate.
         */
        counter++;
    }}

現在來看一個有效的例子:

 class GoodExample {
    private static volatile int temperature;

    //Called by some other thread than main
    public static void todaysTemperature(int temp){
        // This operation is a single operation, so you 
        // do not need compound atomicity
        temperature = temp;
    }

    public static void main(String[] args) throws Exception{
        while(true){
           Thread.sleep(2000);
           System.out.println("Today's temperature is "+temperature);
        }
    }}

現在,為什么你不能使用private static int temperature?實際上你可以(在某種意義上說你的程序不會爆炸或者其他東西),但是temperature另一個線程的改變可能對主線程“可見”,也可能不是“可見”。

基本上這意味著你的應用甚至可能。Today's temperature is 0如果你使用volatile,它會永遠寫作(在實踐中,這個值最終會變得可見。但是,你不應該冒險在必要時不使用volatile,因為它可能會導致令人討厭的錯誤(由完全構造的對象等引起)。 )。

如果將volatile關鍵字放在不需要的東西上volatile,它不會影響代碼的正確性(即行為不會改變)。在性能方面,它將取決于JVM實現。從理論上講,由于編譯器無法進行重新排序優化,不得不使CPU緩存等無效,因此可能會出現微小的性能下降,但再次編譯器可以證明多個線程無法訪問您的字段并刪除volatile關鍵字的影響完全并將其編譯為相同的指令。

編輯:
回復此評論:

好的,但是為什么我們不能讓todaysTemperature同步并為溫度創建一個同步的getter?

你可以,它會表現正常。您可以使用的任何東西volatile都可以完成synchronized,但反之亦然。volatile如果可以,您可能會有兩個理由:

  1. 減少錯誤:這取決于上下文,但在許多情況下使用volatile不太容易出現并發錯誤,例如在持有鎖時阻塞,死鎖等。

  2. 性能volatile更高:在大多數JVM實現中,可以具有更高的吞吐量和更好的延遲。然而,在大多數應用中,差異太小而無關緊要。


查看完整回答
反對 回復 2019-08-26
?
絕地無雙

TA貢獻1946條經驗 獲得超4個贊

易失性在無鎖算法中最有用。當您不使用鎖定來訪問該變量并且您希望一個線程所做的更改在另一個線程中可見時,或者您希望創建“發生后”關系以確保計算是不再重新訂購,以確保在適當的時間可見變化。

JMM食譜介紹了哪些操作可以被重新排序,哪些不能。


查看完整回答
反對 回復 2019-08-26
?
PIPIONE

TA貢獻1829條經驗 獲得超9個贊

volatile 關鍵字保證volatile變量的值總是從主內存中讀取,而不是從Thread的本地緩存中讀取。

來自java并發教程

使用volatile變量可以降低內存一致性錯誤的風險,因為對volatile變量的任何寫入都會建立與之后讀取相同變量的先發生關系

這意味著對volatile變量的更改始終對其他線程可見。它還意味著當線程讀取volatile變量時,它不僅會看到volatile的最新更改,還會看到導致更改的代碼的副作用。

關于你的查詢:

我怎么知道何時應該標記變量volatile?在確定多線程代碼中哪些變量應該是易變的時,有哪些經驗法則?

如果您認為所有讀者線程始終獲得變量的最新值,則必須將變量標記為 volatile

如果您有一個編寫器線程來修改變量和多個讀取器線程的值來讀取變量的值,那么volatile修飾符可以保證內存的一致性。

如果您有多個線程來寫和讀取變量,volatile單獨使用修飾符并不能保證內存一致性。你必須synchronize在代碼或使用高水平并發結構,如Locks,Concurrent CollectionsAtomic variables等。



查看完整回答
反對 回復 2019-08-26
  • 3 回答
  • 0 關注
  • 811 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號