簡體   English   中英

volatile和synced有什么區別?

[英]What is the difference between volatile and synchronized?

我正在嘗試查看volatile在這里如何工作。 如果我將cc聲明為volatile ,則輸出如下。 我知道線程執行輸出時間不同時間,但我讀的地方, volatile是一樣synchronized ,所以為什么我得到這個輸出? 如果我使用Thread1兩個實例,那有關系嗎?

2Thread-0
    2Thread-1
    4Thread-1
    3Thread-0
    5Thread-1
    6Thread-0
    7Thread-1
    8Thread-0
    9Thread-1
    10Thread-0
    11Thread-1
    12Thread-0
public class Volexample {
    int cc=0;

    public static void main(String[] args) {
        Volexample ve=new Volexample();
        CountClass count =ve.new  CountClass();
        Thread1 t1=ve.new Thread1(count);
        Thread2 t2=ve.new Thread2(count);
        t1.start();
        t2.start();
    }

    class Thread1 extends Thread{
        CountClass count =new  CountClass();

        Thread1(CountClass count ){
            this.count=count;
        }

        @Override
        public void run() {
            /*for(int i=0;i<=5;i++)
            count.countUp();*/
            for(int i=0;i<=5;i++){
                cc++;
                System.out.println(cc + Thread.currentThread().getName());
            }
        }
    }

    class Thread2 extends Thread {
        CountClass count =new  CountClass();

        Thread2(CountClass count ){
            this.count=count;
        }

        @Override
        public void run(){
            /*for(int i=0;i<=5;i++)
            count.countUp();*/
            for(int i=0;i<=5;i++){
                cc++;
                System.out.println(cc + Thread.currentThread().getName());
            }
        }
    }

    class CountClass{
        volatile int count=0;
        void countUp(){
            count++;
            System.out.println(count + Thread.currentThread().getName());
        }
    }
}

在Java中, volatile關鍵字的語義定義得很好。 它們確保其他線程將看到對變量的最新更改。 但是它們不會使讀取-修改-寫入操作成為原子操作。

因此,如果ivolatile而您使用i++ ,則可以保證讀取i的最新值,並且可以保證其他線程會立即看到您對i的寫入,但是不能保證兩個線程不會交錯讀取它們。 / modify / write操作,以便兩個增量具有單個增量的效果。

假設i是一個易失性整數,其值初始化為零,除此以外沒有寫操作,並且有兩個線程執行i++; ,可能會發生以下情況:

  1. 第一個線程讀取零,即i的最新值。
  2. 第二個線程讀取零,也是i的最新值。
  3. 第一個線程將其讀取的零遞增,得到一個。
  4. 第二個線程將其讀取的零遞增,也得到一。
  5. 第一個線程將其計算的結果寫入i
  6. 第二個線程將其計算的結果寫入i
  7. 寫入i的最新值是1,因此現在訪問i任何線程都將看到1。

請注意,即使每個線程始終讀取任何其他線程寫入的最新值,增量也會丟失。 volatile關鍵字提供可見性,而不是原子性。

您可以使用synchronized來形成復雜的原子操作。 如果只需要簡單的類,則可以使用Java提供的各種Atomic*類。

Java volatile關鍵字用於將Java變量標記為“正在存儲在主存儲器中”。 這意味着,對易失性變量的每次讀取都將從計算機的主內存中讀取,而不是從緩存中讀取,對易失性變量的每次寫入都將被寫入主內存中,而不僅是高速緩存。

它保證您正在訪問此變量的最新值。

PS使用較大的循環來發現錯誤。 例如,嘗試迭代10e9次。

使用volatile的用例是從映射到設備寄存器的內存中讀取/寫入,例如在微控制器上,其中CPU以外的其他東西正在向該“內存”地址讀取/寫入值,因此編譯器不應將變量優化掉。

暫無
暫無

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

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