Java 中的 volatile

volatile 是Java虚拟机提供的轻量级的同步机制。

  1. 保证可见性
  2. 不保证原子性
  3. 禁止指令重排

可见性

当多个线程操做同一个变量时,每一个线程都会将该变量拷贝一份到本身工做内存中,而后线程完成操做以后,将变量写回主内存。所以可见性就是一个线程在修改变量以后,回通知其余线程,告知改变量已经被修改了。
首先建立一个资源类java

class MyData {
    volatile int number = 0;
    public void setNumber () {
        this.number = 60;
    }
    public void numberPlus() {
        this.number++;
    }
}
// 多线程下测试
public static void main(String[] args) {
   MyData myData = new MyData();
   new Thread(() -> {
            System.out.println(myData.number);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myData.setNumber();
            System.out.println(myData.number);
        }, "AAA").start();;

        while(myData.number == 0) {
        }
}

当使用 volatile 修饰 number 以后,程序回输出 0 和 60 以后执行完成退出。
当没有使用 volatile 修饰 number,程序回输出 0 和 60 以后一直保持执行(死循环),不退出。
由此能够看出,volatile 修饰的变量在修改后,回通知其余线程,保证可见性。多线程

原子性

class MyData {
    volatile int number = 0;
    public void setNumber () {
        this.number = 60;
    }
    public void numberPlus() {
        this.number++;
    }
    AtomicInteger atomicInteger = new AtomicInteger(); // 默认为0
    public void atomicAdd() {
        atomicInteger.getAndIncrement();
    }
}
public static void main(String[] args) {
    MyData myData = new MyData();
    for(int i=0; i<20; i++) {
            new Thread(() -> {
                for(int j=0; j<1000; j++) {
                    myData.numberPlus();
                    myData.atomicAdd();
                }
            }, String.valueOf(i)).start();;
        }

        while(Thread.activeCount() >2) {
            Thread.yield();
        }
        System.out.println(myData.number);
        System.out.println(myData.atomicInteger);
}

程序输出 number 的值小于20000,atomicIntege r等于20000。
由于 volatile 不保证原子性,因此在多线程下操做 number 会出现值被覆盖的问题,也就是一个线程尚未完成++,另外一个线程就取出了 number 进行++, 最后致使值小于了 20000。
解决 volatile 原子性问题,可使用 AtomicInteger性能

指令重排

为了提升性能,编译器和处理器经常会进行指令重排,在多线程环境下,因为指令重排,致使代码的执行顺序和咱们书写代码顺序不一致,最终变量可否保持一致是没法肯定的,结果没法预测。测试

相关文章
相关标签/搜索