Java中volatile关键字你真的理解了吗?
面:你怎样理解volatile关键字时?
我:不加思索的说出,volatile修饰的成员变量,可保证线程可见性、不保证原子性和禁止指令重排。
面:你能谈谈什么是线程可见性吗?
我:各个线程对主内存中共享变量的操作都是各个线程各自拷贝到自己的工作内存进行操作,操作完成后再写回主内存中的.例如一个线程AAA修改了共享变量X的值还未写回主内存中时 ,另外一个线程BBB又对
内存中的一个共享变量X进行操作,但此时A线程工作内存中共享变量X对线程B来说并不不可见。这种工作内存与主内存同步延迟现象就造成了可见性问题。
面:你能通过代码验证线程可见性吗?
我: 好的,写出以下代码,以为很完美,运行也正常,心里美滋滋
class Child{
private volatile boolean cry = false;
public boolean isCry() {
return cry;
}
public void setCry(boolean cry) {
this.cry = cry;
}
}
public class MainTest {
public static void main(String[] args) {
Child child = new Child();
new Thread(()->{
try {
System.out.println("开始循环");
while (!child.isCry()) {
System.out.println("观察宝宝。。。。。");
};
System.out.println("结束循环");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
child.setCry(true);
System.out.println("宝宝醒了。。。。");
}).start();
System.out.println("===============");
}
}
面:你把volatile关键字删除,然后在运行一下?
我:运行一下发现,也能正常结束,我靠为什么会这样呢?我心里开始慌了,然后支支吾吾的。。。。
面:你看过System.out.println();的源码吗?
我:我又慌了,我说没看过(其实真没看过),肯定感觉我平时不怎么思考,而且刚才还再问volatile关键字怎么跳到这了呢。。。。
面:因为println()方法里面加了synchronized,而你在循环里里面调用了该方法,所以你懂了吧
public void println(String x) { synchronized (this) { print(x); newLine(); } }
我:我说大致明白了,因为synchronized能保证线程安全,肯定也具有线程可见性。
面:你这样理解也行,但是在使用了synchronized上锁这个操作后线程会做以下操作:
1.获得同步锁
2.清空工作内存
3.从主内存中拷贝对象副本到本地内存
4.执行代码(打印语句或加加操作)
5.刷新主内存数据
6.释放同步锁
面:volatile不能保证原子性,那你再不加锁的情况怎样保证原子性
我:我会结合java.util.concurrent.atomic包下的类配合使用,因为该包下的类可以保证原子性,通过CAS(比较并交换,个人理解:轻量级自旋锁)方式
面:你了解指令重排的含义吗?
我:大概了解一点,比如n++;它其实会被编译成四条指令,
//伪代码 public void test(){ n++;
} //反编译字节码 public void test(); Code: 0: aload_0 1: dup 2: getfield #2 // Field n:I 5: iconst_1 6: iadd 7: putfield #2 // Field n:I 10: return }
面:恩,那你有时间可以内存屏障的概念,这样才能更深入的理解。
我:好的
面:那你在工作中如何使用volatile?
我:DCL单例模式,其它场景主要使用volatile的线程可见性
public class DCLSingleton { private static volatile DCLSingleton instance; private DCLSingleton(){ } public static DCLSingleton getInstance(){ if(null == instance){ synchronized (DCLSingleton.class){ if(null == instance){ instance = new DCLSingleton(); } } } return instance; } }
原文地址:https://www.cnblogs.com/hyf-huangyongfei/p/12974453.html
- Java常用工具类之压缩解压
- Java常用工具类之MD5加密
- Java常用工具类之发送邮件
- Spring Boot入门
- IDEA使用
- JFinal极速开发框架使用笔记(二) 两个问题,一个发现
- JFinal极速开发框架使用笔记(三) 分析Model和ActiveRecord
- JFinal极速开发框架使用笔记(四) _JFinalDemoGenerator实体类生成及映射自动化
- Python语言做数据探索教程
- Java常用工具类之时间转换(注释乱码,全)
- Java常用工具类之RegexpUtils,正则表达式工具类
- 短信接口发送验证码倒计时以及提交验证
- Java常用工具类之IO流工具类
- JFinal极速开发框架使用笔记
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Python|Numpy的常用操作
- 提速72倍,在Python里面调用Golang函数
- JUC学习之基础
- 【DB笔试面试841】在Oracle中,如何跟踪tnsping过程?
- 系统设计:如何让系统高可用?
- 什么是事务隔离
- Python|Pandas的常用操作
- C++设计模式笔记(01)-设计模式的介绍
- 【DB笔试面试842】在Oracle中,如何启动Oracle数据库的监听日志?
- 【揭秘】C语言类型转换时发生了什么?
- JUC学习之8锁现象
- TensorFlow惊现大bug?网友:这是逼着我们用PyTorch啊!
- 机器学习|用Q-Learning走迷宫
- C++设计模式笔记(03-02) - Template Method_模板方法(下)
- 从零开始学习华为路由交换 | OSPF修改计时器