线程安全的原因及解决方法

一.线程的抢占式执行

我们发现,我们创建两个线程分别执行add方法50000次,理想状态下count最后应该是100000才对,但是从打印的结果看,不仅相差甚远,而且每一次的结果都不相同,这又是为什么呢?

原子性问题:一个操作可以被拆分成多步实现,比如上面的count++(load,add,save)

解决方法

加锁:synchronized

其原理就是当一个线程调用这个方法时,就会获取锁对象,当其他线程也要调用这个方法时,就会发生阻塞,简单来说就是把你拒之门外,因为你门被反锁了,只有当门里面的人出来(释放锁对象),此时才可以重新调用这个方法

二.内存可见性

当一个变量被内存重复读的时候,如果一段时间内没有发生改变,此时可能会触发编译器的优化机制,直接从寄存器中读取数据,读取速度非常快,以至于当我们以后改变此值时,编译器还是以原来的值读

解决方法

volatile保证内存关键性,在写入volatile修饰的变量时,改变工作内存中变量副本的值,且将改变的值刷新到主内存中,在读入volatile修饰的变量时,将最新的值刷新到工作内存中,工作内存读取变量副本的值。

三.指令重排序

以单例模式中的懒汉模式为例

这里不仅有读操作,而且还有写操作

思考一个问题:创建对象过程经过了哪些步骤

1.申请内存空间

2.调用构造方法,将这块空间分配给对象

3.将内存空间的地址赋值给lazy引用

在正常情况下,编译器都是按照123顺序执行的

但是,又是由于提高效率----->编译器优化,可能会出现132的顺序情况

如果按照132顺序来进行

当线程1执行完1,3后,被cpu切了出去,这时候线程2进来,由于此时lazy引用已经被赋值了,不为null,所以线程2直接返回,但是此时的对象还没有构造完,是一个非法的对象,问题也就此产生了

解决方法

还是volatile:

故volatile不仅可以解决内存可见性问题,而且还可以解决指令重排序问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值