探索Volatile
2020-01-15 本文已影响0人
DH大黄
本文是学习悟空老师的视频教程线程八大核心基础后所做的心得笔记,想更加具体了解其中知识的小伙伴可以前往慕课网悟空老师的课程中进行学习
探索Volatile
概念:
volatile是一种同步机制,比synchronized或者lock相关类更轻量,因为使用volatile并不会发生上下文切换等开销很大的行为
如果一个变量被修饰成volatile,那么JVM就知道了这个变量可能会被并发修改
开销比较小,但是能力也相对应的比较小。做不到像synchronized那样的原子保护,只能在很有限的场景下使用
适用场合:(只适用于原子操作,需要可见性/禁止重排序)
可见性,禁止重排序(volatile只能修饰属性,一旦对这个属性修饰了,编译器便不会对这个属性进行指令重排序)
-
例如boolean flag,只有被赋值,没有其他操作(取值校验之类的操作)
-
作为刷新之前变量的触发器(近朱者赤,在volatile之前的操作一定是最新的 happens-before)
package com.hbj.learning.jmm;
/**
* 作为触发器
*
* @author hbj
* @date 2020/1/15 22:01
*/
public class VolatileUse {
private static boolean flag = false;
private static int i = 0;
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("增加前的i" + i);
i++;
System.out.println("i已经加完啦!");
flag = true;
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
while (!flag) {
System.out.println("等待另一个线程对i进行处理");
}
System.out.println("被另一个线程加完的i为" + i);
}
});
thread2.start();
thread1.start();
}
}
不适用场合:
非原子性操作:
例如a++
a++可以拆分成三步:获取a,a+1,将结果赋值给a。volatile只能保证给a赋值后能被其它线程感知到,但是给a赋值前的操作其他线程是不能感知的。(volatile不保证原子性)
注意:
- volatile因为提供了可见性,被它修饰的属性不会被线程缓存,始终是从主存中读取的
- happens-before保证,一旦对参数赋值成功,后续的操作都能够获取到最新赋值的结果
- 使long,double的赋值成为原子性的操作