堆中对象是线程共享的,为什么还需要用volatile来修饰对象?
Posted zhangjin1120
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆中对象是线程共享的,为什么还需要用volatile来修饰对象?相关的知识,希望对你有一定的参考价值。
volatile有两个作用,一是禁止指令重排序,二个是保证共享变量对所有线程的内存可见性。禁止指令重排序,在单例模式中防止出现空指针异常。对于保证内存可见性,堆中对象明明是线程共享的,为什么还需要用volatile来修饰对象?
多线程对共享变量的修改分为很多步骤。举个简单的例子:
public class VolatileTest {
private static boolean flag = true;
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread(() -> {
while (flag){
//注意在这里不能有输出
};
System.out.println("threadA over");
});
threadA.start();
//休眠100毫秒,让线程A先执行
Thread.sleep(100);
//主线程设置共享变量flag等于false
flag = false;
System.out.println("主线程执行完毕");
}
}
输出:主线程执行完毕
,线程A一直死循环。
添加volatile后,输出是:
主线程执行完毕
threadA over
Process finished with exit code 0
死循环产生的原因:主线程把自己工作内存的flag值设置成false后,同步到主内存,此时主内存flag=false。线程A并没有读取到主内存最新的flag值(false),线程A工作内存一直占着cpu时间片,不会从主内存更新最新的flag值,线程A看不到主内存最新值,A线程使用的值和主线程使用值不一致。
简单的讲,main线程修改共享变量的值后,没有及时同步到A线程。
volatile是如何解决这个问题的?
volatile实现内存可见性是通过store和load指令完成的;也就是对volatile变量执行写操作时,会在写操作后加入一条store指令,即强迫线程将最新的值刷新到主内存中;而在读操作时,会加入一条load指令,即强迫从主内存中读入变量的值。
有没有急需一张java内存分布图?
volatile,synchronized可见性,有序性,原子性代码证明(基础硬核)
【Java多线程】内存模型JMM—主内存与工作内存分析
JVM内存分配机制之栈上分配与TLAB的区别
Java堆内存是线程共享的!面试官:你确定吗?
Java内存模型之可见性分析
volitale 怎么保证可见性
以上是关于堆中对象是线程共享的,为什么还需要用volatile来修饰对象?的主要内容,如果未能解决你的问题,请参考以下文章
2020 Java 面试题 小结 (答案慢慢补上,有错误请指出)