线程 -----线程不安全 为什么

116 阅读2分钟
public class ThreadExample implements Runnable {


    private static int count;
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }

    public static void main(String[] args) {
        ThreadExample threadExample=new ThreadExample();
        Thread thread1=new Thread(threadExample);
        Thread thread2=new Thread(threadExample);
        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(count);

    }
}

打印结果: 11084

分析原因:

首先理解下线程和进程的区别:

进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位;

线程是进程的一个执行路径,一个进程至少有一个线程,多个线程则会共享进程中的资源;

线程像病毒一样,不能够独立的存活于世间,需要寄生在宿主细胞中。线程也是不能够独立的生存在系统中,线程需要依附于进程存在。

程序执行count++这个操作时,JVM将会分为三个步骤完成(非原子性):

  1. 某线程从内存中读取count
  2. 某线程修改count值。
  3. 某线程将count重新写入内存。 count++的3个步骤,由于线程会共享进程中的资源,所以在这三步中,任何一步都可能被其他线程打断,导致count值还没来得及写入,就被其他线程读取或写入。

出错流程

假如count值为1,线程1读取到count值后,将count修改为2,此时还没来得及将结果写入内存,内存中的count值还是1。

另一个线程2,读取到count值为1后,也将其修改为2,并成功写入内存中,此时内存中的count值变为了2。

随后线程1也将count的结果2写入到内存中,count在内存中的结果依然是2(理应为3)。

上述场景中,两个线程各自执行了一次count++,但count值却只增加了1,这就是问题所在。