volatile和synced有什么区别?

use*_*845 -1 java multithreading volatile synchronized java-memory-model

我正在尝试看看volatile这里的工作方式。如果声明ccvolatile,则输出如下。我知道线程执行输出有时会有所不同,但是我读到的volatile内容与相同synchronized,那么为什么要获得此输出?如果我使用两个实例,Thread1那有关系吗?

    2线程-0
    2线程1
    4线程1
    3线程-0
    5线程1
    6线程-0
    7线程1
    8线程-0
    9线程1
    10线程-0
    11线程1
    12线程-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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*rtz 5

在Java中,volatile关键字的语义定义得很好。它们确保其他线程将看到对变量的最新更改。但是它们不会使读取-修改-写入操作成为原子操作。

因此,如果iis volatile和you do i++,则可以保证读取的最新值,i并且可以保证其他线程会i立即看到您的写入操作,但是不能保证两个线程不会交织它们的读/修改/写操作。因此,两个增量具有单个增量的效果。

假设i是一个易失性整数,其值初始化为零,除此以外没有写操作,并且有两个线程这样做i++;,可能会发生以下情况:

  1. 第一个线程读取零,最新值为i
  2. 第二个线程读取零,也是最新值i
  3. 第一个线程将其读取的零递增,得到一个。
  4. 第二个线程将其读取的零递增,也得到一。
  5. 第一个线程将其计算的内容写入i
  6. 第二个线程将其计算的内容写入i
  7. 写入的最新值i是1,因此i现在访问的任何线程都将看到1。

请注意,即使每个线程始终读取任何其他线程写入的最新值,增量也会丢失。该volatile关键字给出的知名度,而不是原子。

您可以synchronized用来形成复杂的原子操作。如果只需要简单的Atomic*类,则可以使用Java提供的各种类。