簡體   English   中英

易失性和同步

[英]Volatile and Synchronized

有一些我尚未理解的同步和易失性。

我理解一個線程可以在本地安全地更改。 從我到目前為止所讀到的是synchronized> volatile。

假設我有一個不長或雙的參數,所以基本上是一個標准的整數(沒有原子)。

我有一個同步方法,我用這個Integer做了很多工作。 所有線程都會獲得此Integer的更新版本嗎? 或者我是否必須宣布它是不穩定的?

public class stackoverflow {

    private int x = 0;

    public synchronized void rechnen(){ 
        //dosomething   
    }
}

基本上在rechnen()完成后,我有10000個線程,所有都會得到x的更新版本,因為我的方法是同步的? 或者我是否必須宣布它是不穩定的?

是的,他們將獲得更新版本。 synchronized保證兩件事:變化的可見性和原子性。 volatile只是保證變化的可見性。 Java保證同步塊內的代碼不會被優化(通過混合synchronized塊內外的命令),因此對於其中的變量的每次更改,在同步塊結束后對所有線程都是可見的。

是的,他們將獲得更新版本,但前提是他們自己進入同步塊。 如果他們沒有在同一個對象上輸入同步塊(鎖定同一個監視器),則無法保證他們會看到更新。

如果您不希望其他線程進入同步塊,則必須將變量聲明為volatile。

@partlov已經回答了你的問題,所以作為旁注,還有一些你可能想要考慮的事情。

不要將synchronized用作修飾符

將方法聲明為synchronized時,它使用監視器。 在Java中,每個Object恰好是一個監視器,在這種情況下使用了類實例。 所以你的例子有效地成為:

public void rechnen(){ 
    synchronized(this) {
        //dosomething
    }   
}

現在這會帶來潛在的問題,因為您正在泄漏顯示器。 應用程序的其他部分可以使用同一個監視器同步完全不相關的代碼,這些代碼可能導致/導致性能下降,或者更糟糕的是,當它相關時可能導致意外的死鎖。

因此,主要建議是始終保持監視器的私密性。 所以類似於:

public class stackoverflow {
    private final Object monitor = new Object();
    private int x = 0;

    public void rechnen(){
         synchronized(monitor) {
            //dosomething
         } 
    }
}

知道你的Api

volatilesynchronized有許多用於特定並發目的的工具。 其中大多數使用volatilesynchronizedCAS操作的混合 例如, AtomicInteger為您提供了原子整數運算,其爭用程度遠低於synchronized 所以盡量熟悉java.util.concurrent

代碼中已經存在同步方法。 此外,您需要將x設置為易失性,如下所示

private volatile int x = 0;

這將確保訪問此volatile字段的線程將首先從主內存中讀取其當前值,而不是使用潛在的CPU緩存值

因此,您可以確保您的代碼是線程安全的

聲明private volatile int x = 0; 它將滿足您的目的。 為了更好地理解,請參閱AtomicInteger的實現。

暫無
暫無

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

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