资讯专栏INFORMATION COLUMN

并发编程安全问题:可见性、原子性和有序性

pcChao / 515人阅读

摘要:线程切换带来的原子性问题我们把一个或者多个操作在执行的过程中不被中断的特性称为原子性。编译优化带来的有序性问题顾名思义,有序性指的是程序按照代码的先后顺序执行。

缓存导致的可见性问题
一个线程对共享变量的修改,另外一个线程能够立刻看到,称为可见性

在多核下,多个线程同时修改一个共享变量时,如++操作,每个线程操作的CPU缓存写入内存的时机是不确定的。除非你调用CPU相关指令强刷。

线程切换带来的原子性问题
我们把一个或者多个操作在CPU执行的过程中不被中断的特性称为原子性。

高级语言里一条语句往往需要多条CPU指令完成。例如count += 1,至少需要三条CPU指令:

指令1:首先,需要把变量count从内存加载到CPU的寄存器;

指令2:之后,在寄存器中执行+1操作;

指令3:最后,将结果写入内存(缓存机制导致可能写入的是CPU缓存而不是内存)。

操作系统做任务切换,可以发生在任何一条CPU指令执行完,而不是高级语言里的一条语句。

编译优化带来的有序性问题
顾名思义,有序性指的是程序按照代码的先后顺序执行。
public class Singleton {
    static Singleton instance;

    static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) instance = new Singleton();
            }
        }
        return instance;
    }
}

在new操作上,我们以为 的new操作应该是:

分配一块内存M;

在内存M上初始化Singleton对象;

然后M的地址赋值给instance变量。

但是实际上优化后的执行路径却是这样的:

分配一块内存M;

将M的地址赋值给instance变量;

最后在内存M上初始化Singleton对象。

优化后会导致什么问题呢?我们假设线程A先执行getInstance()方法,当执行完指令2时恰好发生了线程切换,切换到了线程B 上;如果此时线程B也执行getInstance()方法,那么线程B在执行第一个判断时会发现 instance != null ,所以直接返回 instance,而此时的instance是没有初始化过的,如果我们这个时候访问 instance 的成员变量就可能触发空指针异常。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74998.html

相关文章

  • 猫头鹰的深夜翻译:Volatile的原子, 可见有序

    摘要:有可能一个线程中的动作相对于另一个线程出现乱序。当实际输出取决于线程交错的结果时,这种情况被称为竞争条件。这里的问题在于代码块不是原子性的,而且实例的变化对别的线程不可见。这种不能同时在多个线程上执行的部分被称为关键部分。 为什么要额外写一篇文章来研究volatile呢?是因为这可能是并发中最令人困惑以及最被误解的结构。我看过不少解释volatile的博客,但是大多数要么不完整,要么难...

    Lionad-Morotar 评论0 收藏0
  • 来,了解一下Java内存模型(JMM)

    摘要:因为管理人员是了解手下的人员以及自己负责的事情的。处理器优化和指令重排上面提到在在和主存之间增加缓存,在多线程场景下会存在缓存一致性问题。有没有发现,缓存一致性问题其实就是可见性问题。 网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。本文,就来整体的...

    kviccn 评论0 收藏0
  • 来,了解一下Java内存模型(JMM)

    摘要:因为管理人员是了解手下的人员以及自己负责的事情的。处理器优化和指令重排上面提到在在和主存之间增加缓存,在多线程场景下会存在缓存一致性问题。有没有发现,缓存一致性问题其实就是可见性问题。 网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。本文,就来整体的...

    eccozhou 评论0 收藏0
  • 浅谈Java并发编程系列(四)—— 原子可见有序

    摘要:内存模型是围绕着在并发过程中如何处理原子性可见性和有序性这个特征来建立的,我们来看下哪些操作实现了这个特性。可见性可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。 Java内存模型是围绕着在并发过程中如何处理原子性、可见性和有序性这3个特征来建立的,我们来看下哪些操作实现了这3个特性。 原子性(atomicity): 由Java内存模型来直接保证原子性变量操作包括...

    tianren124 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<