设计模式3:单例模式:堆中对象是线程共享的,为什么还需要用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("主线程执行完毕");
        }
}

输出是:

主线程执行完毕

没有输出threadA over,说明线程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 怎么保证可见性

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值