原子性、可见性以及有序性

2023-11-03 19:32
文章标签 原子 有序性

本文主要是介绍原子性、可见性以及有序性,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原子性、可见性以及有序性

  • 原子性: 众所周知,原子是构成物质的基本单位,所以原子代表着不可分。 即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。 最简单的一个例子就是银行转账问题,赋值或者return。比如a = 1;和 return a;这样的操作都具有原子性 原子性不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作! 加锁可以保证复合语句的原子性,sychronized可以保证多条语句在synchronized块中语意上是原子的。

  • 可见性:
    在多核处理器中,如果多个线程对一个变量进行操作,但是这多个线程有可能被分配到多个处理器中运行,那么编译器会对代码进行优化,当线程要处理该变量时, 多个处理器会将变量从主内存复制一份分别存储在自己的片上存储器中,等到进行完操作后,再赋值回主存。 (这样做的好处是提高了运行的速度,因为在处理过程中多个处理器减少了同主内存通信的次数);同样在单核处理器中这样由于备份造成的问题同样存在! 这样的优化带来的问题之一是变量可见性——如果线程t1与线程t2分别被安排在了不同的处理器上面,那么t1t2对于变量A的修改时相互不可见,如果t1A赋值,然后t2又赋新值,那么t2的操作就将t1的操作覆盖掉了, 这样会产生不可预料的结果。所以,即使有些操作时原子性的,但是如果不具有可见性,那么多个处理器中备份的存在就会使原子性失去意义。

  • 非原子性操作 类似a += b这样的操作不具有原子性,在某些JVMa += b可能要经过这样三个步骤:
    - 取出ab - 计算a+b - 将计算结果写入内存 如果有两个线程t1,t2在进行这样的操作。t1在第二步做完之后还没来得及把数据写回内存就被线程调度器中断了,于是t2开始执行,t2执行完毕后t1又把没有完成的第三步做完。这个时候就出现了错误, 相当于t2的计算结果被无视掉了。所以上面的买碘片例子在同步add方法之前,实际结果总是小于预期结果的,因为很多操作都被无视掉了。
    类似的,像a++这样的操作也都不具有原子性。所以在多线程的环境下一定要记得进行同步操作。

  • 有序性 有序性:即程序执行的顺序按照代码的先后顺序执行。

    int i = 0;              
    boolean flag = false;
    i = 1;                //语句1  
    flag = true;          //语句2

    上面代码定义了一个int型变量,定义了一个boolean类型变量,然后分别对两个变量进行赋值操作。从代码顺序上看,语句1是在语句2前面的,那么JVM在真正执行这段代码的时候会保证语句1一定会在语句2前面执行吗? 不一定,为什么呢?这里可能会发生指令重排序(Instruction Reorder)
      下面解释一下什么是指令重排序,一般来说,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。   比如上面的代码中,语句1和语句2谁先执行对最终的程序结果并没有影响,那么就有可能在执行过程中,语句2先执行而语句1后执行。
      但是要注意,虽然处理器会对指令进行重排序,但是它会保证程序最终结果会和代码顺序执行结果相同,那么它靠什么保证的呢?
    再看下面一个例子:

    int a = 10;    //语句1int r = 2;    //语句2
    a = a + 3;    //语句3
    r = a*a;     //语句4

    这段代码有4个语句,那么可能的一个执行顺序是:
    语句2->语句1->语句3->语句4 那么可能不可能是这个执行顺序呢?语句2->语句1->语句4->语句3,这是不可能的,因为处理器在进行重排序时是会考虑指令之间的数据依赖性, 如果一个指令Instruction 2必须用到Instruction 1的结果,那么处理器会保证Instruction 1会在Instruction 2之前执行。

    虽然重排序不会影响单个线程内程序执行的结果,但是多线程呢?下面看一个例子:

    //线程1:
    context = loadContext();   //语句1
    inited = true;             //语句2//线程2:while(!inited ){sleep()
    }
    doSomethingwithconfig(context);

    上面代码中,由于语句1和语句2没有数据依赖性,因此可能会被重排序。假如发生了重排序,在线程1执行过程中先执行语句2,而此时线程2会以为初始化工作已经完成, 那么就会跳出while循环,去执行doSomethingwithconfig(context)方法,而此时context并没有被初始化,就会导致程序出错。 从上面可以看出,指令重排序不会影响单个线程的执行,但是会影响到线程并发执行的正确性。   也就是说,要想并发程序正确地执行,必须要保证原子性、可见性以及有序性。只要有一个没有被保证,就有可能会导致程序运行不正确。

这篇关于原子性、可见性以及有序性的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/340411

相关文章

Lua 脚本在 Redis 中执行时的原子性以及与redis的事务的区别

在 Redis 中,Lua 脚本具有原子性是因为 Redis 保证在执行脚本时,脚本中的所有操作都会被当作一个不可分割的整体。具体来说,Redis 使用单线程的执行模型来处理命令,因此当 Lua 脚本在 Redis 中执行时,不会有其他命令打断脚本的执行过程。脚本中的所有操作都将连续执行,直到脚本执行完成后,Redis 才会继续处理其他客户端的请求。 Lua 脚本在 Redis 中原子性的原因

Redis 篇-深入了解基于 Redis 实现分布式锁(解决多线程安全问题、锁误删问题和确保锁的原子性问题)

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 分布式锁概述         1.1 Redis 分布式锁实现思路         1.2 实现基本的分布式锁         2.0 Redis 分布式锁误删问题         2.1 解决 Redis 分布式锁误删问题         3.0 Redis 分

多线程篇(并发相关类- 原子操作类)(持续更新迭代)

目录 前言 一、原子变量操作类(AtomicLong为例) 1. 前言 2. 实例 二、JDK 8新增的原子操作类LongAdder 三、LongAccumulator类原理探究 前言 JUC包提供了一系列的原子性操作类,这些类都是使用非阻塞算法CAS实现的,相比使用锁实现原子性操作这在性能上有很大提高。 由于原子性操作类的原理都大致相同,这里讲解最简单的AtomicLo

【Java编程的逻辑】原子变量 CAS 显示锁

原子变量 在理解synchronized中有使用synchronized保证原子更新操作,但是使用synchronized成本太高了,需要先获取锁,最后还要释放锁,如果获取不到锁还需要等到。这些成本都是比较高的,对于这种情况,可以使用原子变量。 Java并发包中的基本原子变量类型有以下几种: AtomicBoolean:原子Boolean类型,常用来在程序中表示一个标志位 AtomicIn

正点原子阿尔法ARM开发板-IMX6ULL(二)——介绍情况以及汇编

文章目录 一、裸机开发(21个)二、嵌入式Linux驱动例程三、汇编3.1 处理器内部数据传输指令3.2 存储器访问指令3.3 压栈和出栈指令3.4 跳转指令3.5 算术运算指令3.6 逻辑运算指令 一、裸机开发(21个) 二、嵌入式Linux驱动例程 三、汇编 我们在进行嵌入式 Linux 开发的时候是绝对要掌握基本的 ARM 汇编,因为 Cortex-A 芯片一

CAS与原子操作

什么是原子操作? 原子操作是一种在执行过程中不会被中断的操作。它要么完全执行成功,要么完全不执行,确保在操作完成之前其他线程不会看到操作的中间状态。 原子操作的实现 CAS CAS是由 CPU 提供的原子指令。在硬件级别上确保操作的原子性。不涉及上下文切换,性能高主要用途:单个变量更新 posix锁机制:mutex互斥锁、spinlock自旋锁 互斥锁依赖CAS,且涉及上下文切换,开销大

C++ 原子变量atomic variable

原子变量 原子变量(atomic variable)是 C++11 引入的一种同步机制,用于在多线程环境中进行无锁的、线程安全的操作。原子变量的操作是不可分割的,即在执行过程中不会被其他线程中断,从而避免了数据竞争和不一致的问题。原子变量位于 头文件中。 基本概念 原子性 原子性:一个操作是原子的,意味着它在执行过程中不会被其他线程中断。原子操作要么完全执行,要么完全不执行,不存在部分执行

多线程篇(可见性 原子性 有序性(原子性))(持续更新迭代)

目录 一、synchronized(关键字)(并发编程之美) 1. 前言 2. 内存语义 二、synchronized(关键字)(自我整理(version01)) 1. 前言 2. 线程安全 3. 什么是synchronized关键字? 4. synchronized实现方式 4.1. 修饰实例方法 4.2. 修饰静态方法 4.3. 修饰代码块 5. synchroni

【正点原子K210连载】第三十四章 image图像滤波实验 摘自【正点原子】DNK210使用指南-CanMV版指南

第三十四章 image图像滤波实验 在上一章节中,介绍了image模块中元素绘制方法给的使用,本章将继续介绍image模块中图像滤波方法的使用。通过本章的学习,读者将学习到image模块中图像滤波的使用。 本章分为如下几个小节: 34.1 image模块图像滤波方法介绍 34.2 硬件设计 34.3 程序设计 34.4 运行验证 34.1 image模块图像滤波方法介绍 image模块为Ima

SpringBoot中基于MongoDB的findAndModify原子操作实现分布式锁原理详解

❃博主首页 : 「码到三十五」 ,同名公众号 :「码到三十五」,wx号 : 「liwu0213」 ☠博主专栏 : <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 : 搬的每块砖,皆为峰峦之基;公众号搜索「码到三十五」关注这个爱发技术干货的coder,一起筑基 分布式系统中,分布式锁是一种