【Java进阶知识】多线程导致的不安全现象

在我们设计多线程时,要考虑的问题不外乎就两个——安全、效率!
效率很好理解,那么对于安全呢?多线程为什么会不安全?这篇博客总结自己对多线程安全的初步讲解

1.多线程体现出来的不安全

如果现在让我们给定一个类的静态变量COUNT,并且创建20个线程,在每个线程中都对该变量进行+10000操作,那么,在执行完这个整个操作后,我们期望COUNT返回的值应该是20,0000 那是不是就会这样书写代码:

public class UnsafeThread {
    public static int COUNT;    //静态变量大写,基本数据类型在初始化出来后都有默认值
    public static void main(String[] args) {
   //开启20个线程,每个线程对COUNT进行++操作10000次,预期结果200000
        for(int i = 0; i < 20; i++){
             new Thread(new Runnable() {
               @Override
               public void run() {
                   for(int j = 0; j < 10000; j++){
                       COUNT ++;
                   }
               }
           }).start();
        }
        while(Thread.activeCount() > 2){
            Thread.yield();
        }
        System.out.println(COUNT);
     }
}

执行代码,我们得到的结果是20,0000吗?
事实上并不是!并且每次执行的结果都不相同,但都比20,0000小,显然,我们的结果是有问题的

造成这一现象的原因就是线程的不安全导致的!因为我们创建出的20个线程相互之间是平行的,它们的执行也是不分先后的。事实上每次的COUNT++操作都要经历三个步骤:

  1. 从主存上读取到COUNT当前的值
  2. 对COUNT 进行+1操作
  3. 将修改后的COUNT值重新写回主存中

而分为三个步骤就导致一个很大的问题:假设线程1正在进行第二步,对COUNT修改时,此时线程2也开始执行此代码块,当它从主存读取数据时,读到的是线程1未修改之前的数据,对此数据进行操作。此时就导致对COUNT操作不同步,使得很多线程对COUNT的操作最终无效。

所以,简单的来说如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的,否则,它就是不安全的。

2.不安全的原因

(1)原子性:

为了理解原子性我们把一段代码想象成一个房间,每个线程就是要进入这个房间的人。如果没有任何机制保证,A进入房间之后,还没有出来;B 是不是也可以进入房间,打断 A 在房间里的隐私。这个就是不具备原子性的。
那我们应该如何解决这个问题呢?是不是只要给房间加一把锁,A 进去就把门锁上,其他人是不是就进不来了。这样就保证了这段代码的原子性了。
有时也把这个现象叫做同步互斥,表示操作是互相排斥的。

当然要注意,一条 java 语句不一定是原子的,也不一定只是一条指令。比如刚才我们看到的 n++,其实是由三步操作组成的。那么不保证原子性会给多线程带来什么问题呢?显然,就如同上面的示例一样,如果一个线程正在对一个变量操作,中途其他线程插入进来了,如果这个操作被打断了,结果就可能是错误的。

(2)可见性
主内存-工作内存

在这里插入图片描述
如图所示,为了提高效率,JVM在执行过程中,会尽可能的将数据在工作内存中执行,但这样会造成一个问题,共享变量在多线之间不能及时看到改变,这就是可见性。

(3)代码顺序性
什么是代码重排序?

例如,有这样一系列操作:

  1. 去前台取下 U 盘
  2. 去教室写 10 分钟作业
  3. 去前台取下快递

如果是在单线程情况下,JVM、CPU指令集会对其进行优化,比如,按 1->3->2的方式执行,也是没问题,可以少跑一次前台,这种就叫做指令重排序。
显然单线程情况是没问题的,但在多线程场景下就有问题了,什么问题呢。可能快递是在你写作业的10分钟内被另一个线程放过来的,或者被人变过了,如果指令重排序了,代码就会是错误的。

当然,解决多线程不安全也有很多方法,我们以后逐渐学习。

发布了62 篇原创文章 · 获赞 28 · 访问量 6061

猜你喜欢

转载自blog.csdn.net/Moo_Lavender/article/details/103110470