线程安全问题原因及解决方案

什么是线程安全

线程安全问题的最原始原因是操作系统的随机调度/抢占式执行这个这个过程导致的。

线程安全问题:线程安全问题就是是由于代码运行顺序不正确从而导致计算结果出错,或导致整个程序出现bug。


造成线程安全问题的原因及解决方法

造成线程安全问题的原因我们可以分为下面五种👇

  1. 操作系统随机调度/抢占式执行
  2. 多个线程操作同一个变量
  3. 很多操作并非“原子性”
  4. 内存不可见性
  5. 指令重排序

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

操作系统随机调度/抢占式执行

原因

操作系统的随机调度机制可能会让我们的代码随机顺序执行,就很有可能造成逻辑上的错误

解决方法

无,我们就算了解了操作系统的随机调度机制也无法做到控制操作系统的调度。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

多个线程操作同一个变量

原因

当我们多个线程操作同一个变量时,有可能会使得该变量刚被上一个线程改变,但另一线程可能需要用到该变量改变前的值

解决方法

尽量避免多个线程操作同一个变量的情况出现,但是在真正的操作中,有些难避免

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

操作并非“原子性”

原因

我们的操作,例如 = 赋值这些,只需要用到一条机器指令,这样子的操作,被我们称为具有“原子性”;反之,当我们使用++这种操作时,涉及三条机器指令,即两条及两条以上的机器指令,这时我们就可以将其称为并不具有“原子性”。若不具有原子性,我们的操作可能就会被操作系统给打乱了顺序执行。

解决方法

我们可以将不具有原子性的加锁操作或者几行代码给一起“打包”,让操作系统当成一条机器指令。我们的加锁操作需要用到synchronized修饰符。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

内存不可见性

原因

当我们的一个线程修改,另一个线程一直执行读和判断操作时操作系统会自动给我们进行优化,这个过程就很容易造成内存不可见性。

 如图,操作系统可能会将每次读后判断优化成读、判断判断判断判断...这样子会导致每一次判断的都是判断最开始读时候的数据,并不能判断到进行写操作之后改变其数据。

解决方法

针对操作系统的优化,我们是可以告诉操作系统不要进行优化的,通过调用volatile()函数。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

指令重排序

原因

其原因也是由于操作系统的优化,可能是出于集中处理指令的思路,操作系统会将我们的指令重新排序,如下面的三步:①创建t这个变量;②创建一个Thread对象;③将该对象引用赋给t变量。在单线程中,②③顺序改变没有影响。但在多线程中,若有两个线程,另一线程中,想要读取t的引用,若我们是按照②③顺序,另一线程读到t未非null,此时t一定是有对象的,但若按照③②的顺序创建,我们很有可能读到的t是无效对象。

解决方法

和上一个问题解决方法一样,既然是因为操作系统的优化造成的,那么我们就通过volatile函数来告诉操作系统不要优化。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值