有volatile在,变量一定会安全吗?

        在编程中,安全问题一直是我们关注的重点,能否确保程序在多线程的情况下实现安全,这应该一直是各位攻城狮们极其在意的。今天小编就和大家一起接着上篇博客继续聊一聊 关于原子性和可见性的问题!

✎  什么是原子性

      大家都知道,原子是构成物质的最小单位,所以可以将原子性理解成为不可分性,比如数据库中的第一范式,强调的列的原子性,即列不能再进行分割。而原子性在多线程的环境下,可以理解为某一个变量不能同时被多个线程同时操作;

     举个栗子:A、B两个学生同时去应聘同一个职位,而这个职位只能其中一个人就职,也就是说:要么A干,要么B干。所以这个职位就是具有原子性的。

     在Java中,具有原子性的主要有<return a; > 、<a = 2; > 等;那么a++ 或者++a这种操作具有原子性吗?答案是:不具有!因为对于a++这种操作,共需要经历三步:获取a的值--> 执行++ -->将结果赋值给a; 而在这个过程中,并不能保证是单线程操作,或者正是因为无法保证在多线程中的安全性,所以有了automic的原子类来帮助完成a++的安全操作;

     因此,原子性是指不论处理器是单核还是多核,也不管是单线程还是多线程,在同一个时刻只能有一个线程执行操作;

✎ 可见性又是对谁可见

     提起volatile,直接想到的就是volatile是将变量的值维护在内存中,可以确保每个线程的操作访问到的值都是来自内存,可以保证多个线程读取到的是同一份数据。问题来了:

1、为什么就可以维护在内存中一份数据?

2、读取的同一份数据就安全吗?

    解读一:

         之所以可以保证多个线程都读取同一份来自内存的数据,主要跟volatile有关,在线程对变量操作之后,会有store屏障强制将变量的值更新为当前的值;而在某线程来获取该变量值时,volatile又可以使用load屏障指令强制当前线程更新该变量值为当前内存中维护的这个值。这样一来,每次被操作之后,变量的值都会被强制一下,这样无论变量的值更新为多少,每个线程都会拿到这个变量的最新值。

   解读二:

        虽然做到了变量的值是最新的,但是在多线程环境下并不能保证当前变量一定是线程安全的,如果当前有两个线程同时对变量a = 1进行获取和更新操作,然后线程A首先对变量a进行了+1 的操作,而在将+1的结果赋值给a的时候,线程B已经先A线程一步将a的值更新为3,这时候就会出现一个问题:本来线程A只是为了将a变量赋值成2;

        结果由于线程B的提前介入,a的值已经不是线程A期望的结果了,这就是简单的非线程安全的场景。

✎ 如何解决volatile的线程安全问题

      解决线程安全问题,不要忘了开篇时候说道的原子性,多线程会有问题,我们是否可以让它实现原子性的操作??当然可以,就是我们的synchronize关键字,在多个线程对同一个变量进行访问时,做一下控制,只让一个线程来操作,这样就不会出现线程安全问题;最典型的操作:

     单例模式中的双重校验!

    到这里就基本结束了,不知道小编的这些见解有没有帮你解答心中的疑惑呢?

 

    

    

       

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值