可见性: 直接操作主内存,不需要通过工作内存中转,保证了可见性
原子性:它的读和写单独操作是原子的,但是读和写一起就是非原子操作
禁止重排序: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,才能保证前面的可见性 } }