Java线程安全中的有序性浅析
作者:绿仔牛奶_ 发布时间:2023-07-12 03:07:58
什么是有序性
在开发中,我们通常按照从上到下的顺序编写程序指令,并且希望cpu和编译器按照我们预先编写的顺序去执。但往往cpu和编译器为了提高性能、优化指令的执行顺序,会将我们编写好的程序指令进行重排序。
此时如果是在单线程状态下,无论是否进行了重排序都不会影响程序最终的结果
而有序性是指在多线程环境下就可能会由于程序指令重排序后导致最终结果与预期不符的情况
我们以单例模式中的双重检验锁为例
利用new关键字创建一个对象实际上是执行了三个操作
分配内存空间
在内存上(执行构造方法)初始化对象
将初始化后的对象提交给引用(对象引用指向分配好的内存空间地址)
但是当我们在运行程序时,编译器对程序进行重排序优化,经常会将2和3两个步骤进行调换。
// 双重检验锁
public class Singleton {
static Singleton instance;
static Singleton getInstance(){
if (instance == null){
synchronized(Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
上述双重检验锁,在第一次校验instance是否为null时如果不为null,则不用进行后续的初始化的下面的加锁操作,大幅的提高了synchronized的性能。但是在多线程状态下执行上述创建对象的程序,就可能会出现创建的对象instance虽然不为null,但是它可能还没有初始化但是却指向了某片内存空间。
我们就下图进行分析
我们假设A和B两条线程同时创建对象,那么上述的A线程创建instance时为其分配内存空间,正确来讲应该先对instance进行初始化然后将内存地址交给instance,但是由于重排序,却在初始化之前提交了内存地址。那么当线程切换到B,B就会认为instance是一个创建完成的对象就会返回。
双重检验锁的有序性就体现在,创建对象的三个操作被重排序之后可能执行顺序会变成先提交内存地址再初始化导致对象创建失败
解决有序性?
Volatile修饰保证有序性
使用Synchtonized加锁保证有序性
使用Lock加锁保证有序性
来源:https://blog.csdn.net/yuqu1028/article/details/128680948


猜你喜欢
- <?xml version="1.0" encoding="utf-8"?> <L
- 日记基础操作编程期调试代码运营期记录信息记录日常运营重要信息(峰值流量,平均响应时长...)记录应用报错信息(错误堆栈)记录运维过程数据(扩
- 方式1:1. 明确 Spark中Job 与 Streaming中 Job 的区别1.1 Spark Core一个 RDD DAG Graph
- 问题发现今天发生了一件事,令我非常郁闷,就是我在使用一个SDK时,当我调用他的方法时,提示我方法中的参数var1, var2如下:// 方法
- Mybatis基础回顾与高级应用数据库:mysql5.7jdk:15引入依赖<!--引入依赖--> &
- 前提前面写过一篇关于Environment属性加载的源码分析和扩展,里面提到属性的占位符解析和类型转换是相对复杂的,这篇文章就是要分析和解读
- Android 中启动自己另一个程序的activity如何实现可以使用action,举例: 1. 比如建立activity4,我
- IntroC# 9 中进一步增强了模式匹配的用法,使得模式匹配更为强大,我们一起来了解一下吧SampleC# 9 中增强了模式匹配的用法,增
- 一、进程内部的线程同步1、使用lock,用法如下:private static readonly object SeqLock = new
- Java类中字段可以不赋予初始值的原因Java虚拟机会对类的实例对象进行分配内存,在分配内存后,会将内存空间(除了对象头)全部初始化为零值。
- 介绍装饰者模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,增加对象功能来说,装饰模式比生成子类实现更为灵活。
- 智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delet
- 本文实例讲述了Java利用反射自动封装成实体对象的方法。分享给大家供大家参考。具体分析如下:利用此方法的时候需要传递的参数的名称,必须以行号
- 我们springboot项目有自己默认的配置文件,一般地由application.yml和bootstrap.yml组成,前者是模块的配置,
- 前言WebView(网络视图)在Andorid中就是用来显示网页的,下面我们来一起看看它是如何使用的。一、基本使用1.声明权限,WebVie
- 代码如下一、创建EdgeLight.xaml代码如下。<ResourceDictionary xmlns="htt
- JetpackJetpack,我觉得翻译为“飞行器”更好听,因为Google针对编程历史乱象,整理出
- 1.添加引用Windows服务(.NET Framework)2.输入项目名称,选择安装位置,,选择安装框架版本;创建。3.找到MyServ
- 使用了RecyclerView嵌套RecyclerView的方案。购物车的第一个界面为RecyclerView,每个Item里面包含一个店铺
- 背景我们平时在用springboot开发时,要使用事务,只需要在方法上添加@Transaction注解即可,但这种方式只适用单数据源,在多数