多线程(9)volatile的使用

可见性: 直接操作主内存,不需要通过工作内存中转,保证了可见性

原子性:它的读和写单独操作是原子的,但是读和写一起就是非原子操作

禁止重排序:volatile修饰的变量操作位置固定,前面的不能到它后面,它后面的也不能去它前面执行

更多: https://www.jianshu.com/p/9abb4a23ab05

不适用场景

a++  : 非原子的会出错,先读取值得基础上加一赋值

适用场景:

(1)flag = true: 如果一个变量只是被各线程赋值,没有基于先读的基础再写的操作,赋值是原子的,本身有可见性可以代替synchronize实现线程安全

(2)触发器: 底层原理是内存栅栏,也叫屏障指令,说白了就是可以保证线程内存和主内存之间的同步。用了volatile之后,编译器和CPU会识别到,于是就有了同步的功效,

                       可以保证在读取volatile修饰的变量的时候,保证能看到之前的所有写操作,于是就能当作触发器使用。

public class VolatileTest {
    public static void main(String[] args) {
        while (true){
            Vis vis = new Vis();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    vis.setVal();
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    vis.print();
                }
            });
            t1.start();
            t2.start();
        }

    }
}
class Vis{
    int a=0;
    int c = 0;
    volatile int b=0;
    public void setVal(){
        c = 2;
        a=3;
        b=a;  // 前面的非volatile变量操作也都可见
    }

    public void print(){
            System.out.println("b:"+b+",a:"+a+",c="+c); // 要先读取b,才能保证前面的可见性
    }
}

猜你喜欢

转载自www.cnblogs.com/t96fxi/p/13177765.html