可见性:
JAVA内存模型:
java为了加快程序的运行效率,对一些变量的操作是在寄存器或者CPU缓存上进行的,后面再同步到主存中
看上图,线程在运行的过程中,会从主内存里面去去变量,读到自己的空间内,最后再刷新进去,而volatile的出现,使得可以直接去主存中数据,换句话来说,一般情况下更新了数据之后需要等待一段时间刷新主内存来保证数据的统一,volatile让其他线程更快的知道这个改变,因此他修饰的变量具有可见性
指令重排序
volatile禁止指令重排序
指令重排序:为了提高运行效率对代码进行优化,不保证语句执行顺序和代码中一样,但是保证结果一样。
非原子性
原子性:一系列操作要么全部执行,要么都不执行
常见的 i++操作:先取出i的值,+1后,写回,这不是原子操作,进行了三步
1 public class MyThread extends Thread { 2 public volatile static int count; 3 4 private static void addCount() { 5 for (int i = 0; i < 100; i++) { 6 count++; 7 } 8 System.out.println("count=" + count); 9 } 10 11 @Override 12 public void run() { 13 addCount(); 14 } 15 } 16 17 public class Run { 18 public static void main(String[] args) { 19 MyThread[] mythreadArray = new MyThread[100]; 20 for (int i = 0; i < 100; i++) { 21 mythreadArray[i] = new MyThread(); 22 } 23 24 for (int i = 0; i < 100; i++) { 25 mythreadArray[i].start(); 26 } 27 } 28 }
因此这个的结果并不会是10000,因为可能在i++分步操作的时候,会有其他的线程进来取值,而我还没来得及改变地址区域里面的值
比较
1、volatile是轻量级的,只能修饰变量,synchronized是重量级的,还可以修饰方法
2、volatile只能保证数据的可见性,不会阻塞,synchronized既能保证可见性也能保证原子性,会出现争抢锁的情况,会出现阻塞
3、volatile不能保证线程安全,synchronized可以保证线程安全