簡體   English   中英

Java使用synchronized時我是否免費獲得易失性功能?

[英]Java When using synchronized do I get volatile functionality for free?

我讀了幾篇關於並發性問題的帖子,但我仍然不確定某些事情。 我可以說當使用synchronized時,我免費獲得易失性功能,因為當釋放對象的鎖定時,下一個線程總是讀取修改后的對象。 對於volatile,對象的值會立即反映到其他線程。 但是當我使用synchronized時,由於對象的鎖定,不可能立即反映它。 釋放鎖定后,只有另一個線程可以訪問它。 所以我不必關心立即將值反映到其他線程。 我理解這個嗎?

[UPDATE]
示例打印總是1 2 3 4 5 6 7 8 9沒有易失性。

package main;

public class Counter
{
    public static long count = 0;
}

public class UseCounter implements Runnable
{
    public void increment()
    {
        synchronized (this)
        {       
            Counter.count++;
            System.out.print(Counter.count + " ");
        }
    }

    @Override
    public void run()
    {
        increment();
        increment();
        increment();
    }
}

public class DataRace
{
    public static void main(String args[])
    {
        UseCounter c = new UseCounter();

        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        Thread t3 = new Thread(c);

        t1.start();
        t2.start();
        t3.start();
    }
}

不,根據Java內存模型,同步訪問並不暗示易失性訪問(盡管在特定實現中,它可能是,但您不應該依賴於此)

Java語言規范17.4.4(關於Java內存模型):

同步動作引發與動作的同步關系,定義如下:

  • 監視器m上的解鎖動作與m上的所有后續鎖定動作同步(其中“后續”根據同步順序定義)。

  • 對易失性變量v(第8.3.1.4節)的寫入與任何線程對v的所有后續讀取同步(其中“后續”根據同步順序定義)。

volatile對變量進行操作,並在對象的監視器(“鎖定”)上進行synchronized操作。

如果一個線程A剛剛退出對象O上的同步塊,而另一個線程B剛剛讀取了對象O上的volatile變量(實例字段) V ,則兩個線程之間仍然沒有同步關系。 無法保證線程A將看到線程B完成的任何數據修改,反之亦然,直到線程B也在對象O上同步,或者直到線程A也訪問對象O上的易失性字段V.

擁有volatile變量與同步訪問不同。 將變量標記為volatile時,訪問該對象的Thread對象將不會保留本地緩存,並且只會有一個“副本”。 如果你將兩者(synchronized和volatile)結合起來,那么它將始終是更新版本,並且你不會有相互沖突的訪問權限。

您的代碼保證打印1 2 3 4 5 6 7 8 9.原因是如果您有一個序列,如

  1. 線程t1寫入Counter.count
  2. 線程t1解鎖對象c
  3. 線程t2鎖定對象c
  4. 線程t2讀取Counter.count

然后保證步驟4的讀取在步驟1看到寫入。

這與volatile因為不能保證寫入立即反映回存儲器,而是僅保證步驟1中的寫入在步驟3結束時對t2可見。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM