Java多线程之什么是线程不安全、线程不安全的原因


提示:以下是本篇文章正文内容,Java系列学习将会持续更新

一、什么是线程不安全

现象

线程不安全的现象就是预期结果和实际结果不一致。
预期运行结果:0
实际运行结果:随机数

/**
 * 线程不安全的现象
 */
public class Demo {

    // 定义一个被操作的数
    static int r = 0;
    // 定义操作的数
    static final int COUNT = 100_0000;

    static class Add extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < COUNT; i++) {
                r ++;
            }
        }
    }

    static class Sub extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < COUNT; i++) {
                r --;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread add = new Add();
        add.start();
        Thread sub = new Sub();
        sub.start();

        // 等待结束
        add.join();
        sub.join();

        // 理论上还是0, 但是实际现象是吗?
        System.out.println(r);
        // 实际运行结果,并不是100%正确;反而随着COUNT的增大,出错概率也增大
    }
}

when is 线程不安全?

对于开发者,什么情况下会出现线程不安全?
多个线程共享同一块数据,且至少有一个线程对共享数据做修改(写)操作

在多线程的代码中,哪些情况下不需要考虑线程安全问题?
①几个线程之间互相没有任何数据共享的情况下,天生是线程安全的;
 ②几个线程之间即使有共享数据,但都是做读操作,没有写操作时,也是天生线程安全的。

回到目录…

二、造成线程不安全的原因

(1)线程的非原子性操作

程序员的预期是r++和r–是一个原子性的操作。但实际执行起来保证不了原子性
Ⅰ. java代码(高级语言)中的一条语句,很可能对应的多条指令
  r++实质就是r= r+1,变成指令动作:
   ①LOAD_ A // 从内存中把数据加载到寄存器中
   ②ADD 1 // 完成数据加1的操作并写入寄存器中
   ③STORE A // 把寄存器中的值写回到内存中
Ⅱ.线程调度是可能发生在任意时刻的,单看这3条指令,线程调度可能在其中穿插执行,破环了原子性。

(2)内存可见性

内存可见性问题:在多线程共享一个数据块下,一个线程对数据进行修改操作时,其它线程是无法感知的。甚至会被编译器优化到完全不可见的程度。

例如:当两个线程同时操作一个内存,例如一个读一个写,但是当“写线程”进行的修改的时候,“读线程”可能读到修改前的数据,也可能读到修改后的数据,这是不确定的。

不可见的原因
  CPU为了提高数据获取速率,会设置缓存。
  在多核CPU下,每个核都有自己的独占缓存进行数据存取,只有在所有处理结束后,才会将数据同步到主存中。
  所以会导致有些核读取到的是过期的数据。

(3)指令重排序

与编译器优化直接相关:
为了提高程序的执行效率,调整了执行的顺序(调整的目的是为了提高效率,不改变逻辑)
编译器也会自动对顺序进行调整。单线程下调整不会出现问题,多线程下调整会出现大问题


说白了,就是书写指令和执行指令不一致导致的错误。
JVM规定了一些重排序的基本原则: happend-before 规则
简要的解释:
  JVM要求,无论怎么优化,对于单线程的视角,结果不应该有改变。
  但并没有规定多线程环境的情况(并不是不想规定,而是不能规定)
  导致在多线程环境下可能出问题

回到目录…


总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,本文是Java多线程的学习,介绍了线程不安全的现象,以及造成线程不安全的主要原因。之后的学习内容将持续更新!!!

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只咸鱼。。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值