java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释

首先借用阳哥的脑图:

java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释_第1张图片

1、轻量级:是相对jvm的三个特性,volatile只实现了可见性、有序性来说的。

2、可见性:

如下图:线程工作时,会从堆中(主内存)里拷贝变量age=25到各自栈中(工作内存),当任一线程如t1修改值为37,回写到主内存时,需要保障其他所有线程都获知主内存的变量age已更新为37,这就是可见性,即对主内存的修改,得相互知道

java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释_第2张图片

内存模型JMM:分为堆、方法区、栈、寄存器

java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释_第3张图片

java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释_第4张图片

代码测试可见性,可利用main线程以及new一个子线程来印证,若未用volatile关键字修饰的变量,在子线程更新值后,对于main线程是不可见的,无法得到更新值。而使用了volatile之后,值更新线程间是互相可见的。得证volatile具有可见性。

2、非原子性

原子性:不可分割,完整性,线程在执行某个由多项步骤构成的任务时,中间不可以被加塞打断,需要让它完整执行所有步骤。

对于这多项步骤,要么全部成功,任务完成,要么就全部都失败,回退掉。类比数据库事务的原子性。

非原子性,就表示在线程对变量作业务时,volatile不能保障线程的每个任务的完整执行所有步骤。例如:

执行一个:number++自增运算,其任务有以下步骤:

getfield        //读
iconst_1	//++常量1
iadd		//加操作
putfield	//写操作

当高并发时,自增就会出错。比如某个时刻,有几个线程同时拿到number的值都是1的时候,第一个线程自增完成做putfield写操作时,同时其他线程在自己栈空间操作了阻塞在写操作中,等第一个完成后,陆续其他线程也写回了2.造成了写覆盖。相当于有部分线程的操作失效。

解决方案:1、对该业务过程加锁(synchronize修饰,但太杀鸡用牛刀了);2、用jdk里面的atomicinteger API(建议),底层是CAS实现的,计算机原子指令

java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释_第5张图片

3、禁止指令重排

java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释_第6张图片

案例:

java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释_第7张图片

重排后,线程1的x取到了线程2初始化的a的值。导致错误

volatile有序性原理:

java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释_第8张图片

volatile应用场景

在DCL单例模式中(Double-Check-Lock)

java基础理论学习笔记(1)——谈谈对volatile的理解?从可见性、非原子性、禁止指令重排详细解释_第9张图片

你可能感兴趣的:(java基础)