不同关键字的原子性、可见性、有序性之间的比较

2024-08-23 20:36

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

一、多线程中有三个非常重要的特性

1. 原子性

    在一次或者多次操作时,要么所有操作都被执行,要么所有操作都不执行

2. 有序性

    程序执行的顺序按照代码的先后顺序执行,没有进行优化和顺序调整。

    为了提高程序的运行效率,Java可能在JVM编译期和运行期会对代码指令进行一定的优化,不会百分之百的保证代码的执行顺序严格按照编写代码中的顺序执行,但也不是随意进行重排序,它会保证程序的最终运算结果是编码时所期望的。这种情况被称之为指令重排

3. 可见性

   当一个线程对共享变量进行修改后,其他一个线程可以立即看到该变量修改后的最新值

二、说到三个特性,就不得不提Java内存模型(JMM)

       JMM是一种抽象概念,并不真实存在,它描述的是一组规范。JVM运行程序的实体是线程,每个线程都有一个属于自己私有的工作内存。Java内存模型中规定了:所有变量都存储在主内存中,主内存是一块共享内存区域,所有线程都可以访问。

       但是,线程对变量的读取赋值等操作必须在自己的工作内存中进行,在操作之前先把变量从主内存中复制到自己的工作内存中,然后对变量进行操作,操作完成后再把变量写回主内存。因为线程不能直接操作主内存中的变量,所以线程的工作内存中存放的是主内存中变量的一个副本而已。

三、如何保证有序性

Java内存模型的一个叫 Happens-Before 的原则了。如果两个操作的执行顺序无法从Happens-Before原则推到出来,那么可以对它们进行随意的重排序处理了。Happens-Before原则有下面这些原则,希望你能记住:

1. 程序次序原则:一段代码在单线程中执行的结果是有序的。
2. 锁定原则:一个锁处于被锁定状态,那么必须先执行unlock操作后面才能进行lock操作。
3. volatile变量原则:同时对volatile变量进行读写操作,写操作一定先于读操作。
4. 线程启动原则:Thread对象的start方法先于此线程的每一个动作。
5. 线程终结原则:线程中的所有操作都先于对此线程的终止检测。
6. 线程中断原则:对线程interrupt方法的调用先于被中断线程的代码检测到中断事件的发生。
7. 对象终结原则:一个对象的初始化完成先于它的finalize方法的开始。
8. 传递原则:操作A先于操作B,操作B先于操作C,那么操作A一定先于操作C。
9. 除了Happens-Before原则提供的天然有序性,我们还可以用以下几种方式保证有序性:

四、总结一下

特性volatile关键字Lock接口synchronized关键字Atomic变量
原子性无法保障可以保障可以保障可以保障
可见性可以保障可以保障可以保障可以保障
有序性一定程度保障可以保障可以保障无法保障

这篇关于不同关键字的原子性、可见性、有序性之间的比较的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

Python如何实现高效的文件/目录比较

《Python如何实现高效的文件/目录比较》在系统维护、数据同步或版本控制场景中,我们经常需要比较两个目录的差异,本文将分享一下如何用Python实现高效的文件/目录比较,并灵活处理排除规则,希望对大... 目录案例一:基础目录比较与排除实现案例二:高性能大文件比较案例三:跨平台路径处理案例四:可视化差异报

Python Flask实现定时任务的不同方法详解

《PythonFlask实现定时任务的不同方法详解》在Flask中实现定时任务,最常用的方法是使用APScheduler库,本文将提供一个完整的解决方案,有需要的小伙伴可以跟随小编一起学习一下... 目录完js整实现方案代码解释1. 依赖安装2. 核心组件3. 任务类型4. 任务管理5. 持久化存储生产环境

Python批量替换多个Word文档的多个关键字的方法

《Python批量替换多个Word文档的多个关键字的方法》有时,我们手头上有多个Excel或者Word文件,但是领导突然要求对某几个术语进行批量的修改,你是不是有要崩溃的感觉,所以本文给大家介绍了Py... 目录工具准备先梳理一下思路神奇代码来啦!代码详解激动人心的测试结语嘿,各位小伙伴们,大家好!有没有想

Java中的volatile关键字多方面解析

《Java中的volatile关键字多方面解析》volatile用于保证多线程变量可见性与禁止重排序,适用于状态标志、单例模式等场景,但不保证原子性,相较synchronized更轻量,但需谨慎使用以... 目录1. volatile的作用1.1 保证可见性1.2 禁止指令重排序2. volatile的使用

Java中数组与栈和堆之间的关系说明

《Java中数组与栈和堆之间的关系说明》文章讲解了Java数组的初始化方式、内存存储机制、引用传递特性及遍历、排序、拷贝技巧,强调引用数据类型方法调用时形参可能修改实参,但需注意引用指向单一对象的特性... 目录Java中数组与栈和堆的关系遍历数组接下来是一些编程小技巧总结Java中数组与栈和堆的关系关于

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

C#中lock关键字的使用小结

《C#中lock关键字的使用小结》在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时,其他线程无法访问同一实例的该代码块,下面就来介绍一下lock关键字的使用... 目录使用方式工作原理注意事项示例代码为什么不能lock值类型在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时