返回顶部
首页 > 资讯 > 精选 >Java指令重排在多线程环境下怎么解决
  • 212
分享到

Java指令重排在多线程环境下怎么解决

2023-06-30 09:06:27 212人浏览 独家记忆
摘要

本篇内容介绍了“Java指令重排在多线程环境下怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、序言指令重排在单线程环境下有利于提高

本篇内容介绍了“Java指令重排在多线程环境下怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、序言

指令重排在单线程环境下有利于提高程序的执行效率,不会对程序产生负面影响;在多线程环境下,指令重排会给程序带来意想不到的错误。

二、问题复原

(一)关联变量

下面给出一个能够百分之百复原指令重排的例子。

public class D {    static Integer a;    static Boolean flag;        public static void writer() {        a = 1;        flag = true;    }        public static void reader() {        if (flag != null && flag) {            System.out.println(a);            a = 0;            flag = false;        }    }}
1、结果预测

reader方法仅在flag变量为true时向控制台打印变量a的值。

writer方法先执行变量a的赋值操作,后执行变量flag的赋值操作。

如果按照上述分析逻辑,那么控制台打印的结果一定全为1。

2、指令重排

假如代码未发生指令重排,那么当flag变量为true时,变量a一定为1。

上述代码中关于变量a和变量flag在两个方法类均存在指令重排的情况。

public static void writer() {    a = 1;    flag = true;}

通过观察日志输出,发现有大量的0输出。

writer方法内部发生指令重排时,flag变量先完成赋值,此时假如当前线程发生中断,其它线程在调用reader方法,检测到flag变量为true,那么便打印变量a的值。此时控制台存在超出期望值的结果。

(二)new创建对象

使用关键字new创建对象时,因其非原子操作,故存在指令重排,指令重排在多线程环境下会带来负面影响。

public class Singleton {    private static UserModel instance;        public static UserModel getInstance() {        if (instance == null) {            synchronized (Singleton.class) {                if (instance == null) {                    instance = new UserModel(2, "B");                }            }        }        return instance;    }}@Data@AllArgsConstructorclass UserModel {    private Integer userId;    private String userName;}
1、解析创建过程
  • 使用关键字new创建一个对象,大致分为一下过程:

  • 在栈空间创建引用地址

  • 以类文件为模版在堆空间对象分配内存

  • 成员变量初始化

  • 使用构造函数初始化

  • 将引用值赋值给左侧存储变量

2、重排序过程分析

针对上述示例,假设第一个线程进入synchronized代码块,并开始创建对象,由于重排序存在,正常的创建对象过程被打乱,可能会出现在栈空间创建引用地址后,将引用值赋值给左侧存储变量,随后因CPU调度时间片耗尽而产生中断的情况。

后续线程在检测到instance变量不为空,则直接使用。因为单例对象并为实例化完成,直接使用会带来意想不到的结果。

三、应对指令重排

(一)AtomicReference原子类

使用原子类将一组相关联的变量封装成一个对象,利用原子操作的特性,有效回避指令重排问题。

@Data@NoArgsConstructor@AllArgsConstructorpublic class ValueModel {    private Integer value;    private Boolean flag;}

原子类应该是解决多线程环境下指令重排的首选方案,不仅通俗易懂,而且线程间使用的非重量级互斥,效率相对较高。

public class E {    private static final AtomicReference<ValueModel> ar = new AtomicReference<>(new ValueModel());        public static void writer() {        ar.set(new ValueModel(1, true));    }        public static void reader() {        ValueModel valueModel = ar.get();        if (valueModel.getFlag() != null && valueModel.getFlag()) {            System.out.println(valueModel.getValue());            ar.set(new ValueModel(0, false));        }    }}

当一组相关联的变量发生指令重排时,使用原子操作类是比较优的解法。

(二)volatile关键字

public class Singleton {    private volatile static UserModel instance;        public static UserModel getInstance() {        if (instance == null) {            synchronized (Singleton.class) {                if (instance == null) {                    instance = new UserModel(2, "B");                }            }        }        return instance;    }}@Data@AllArgsConstructorclass UserModel {    private Integer userId;    private String userName;}

四、指令重排的理解

1、指令重排广泛存在

指令重排不仅限于Java程序,实际上各种编译器均有指令重排的操作,从软件到CPU硬件都有。指令重排是对单线程执行的程序的一种性能优化,需要明确的是,指令重排在单线程环境下,不会改变顺序程序执行的预期结果。

2、多线程环境指令重排

上面讨论了两种典型多线程环境下指令重排,分析其带来负面影响,并分别提供了应对方式。

  • 对于关联变量,先封装成一个对象,然后使用原子类来操作

  • 对于new对象,使用volatile关键字修饰目标对象即可

3、synchronized锁与重排序无关

synchronized锁通过互斥锁,有序的保证线程访问特定的代码块。代码块内部的代码正常按照编译器执行的策略重排序。

尽管synchronized锁能够回避多线程环境下重排序带来的不利影响,但是互斥锁带来的线程开销相对较大,不推荐使用。

synchronized 块里的非原子操作依旧可能发生指令重排

“Java指令重排在多线程环境下怎么解决”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: Java指令重排在多线程环境下怎么解决

本文链接: https://lsjlt.com/news/327955.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java指令重排在多线程环境下怎么解决
    本篇内容介绍了“Java指令重排在多线程环境下怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、序言指令重排在单线程环境下有利于提高...
    99+
    2023-06-30
  • Java指令重排在多线程环境下的解决方式
    目录一、序言二、问题复原(一)关联变量1、结果预测2、指令重排(二)new创建对象1、解析创建过程2、重排序过程分析三、应对指令重排(一)AtomicReference原子类(二)v...
    99+
    2024-04-02
  • Java指令重排序在多线程环境下如何处理
    这篇文章主要讲解了“Java指令重排序在多线程环境下如何处理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java指令重排序在多线程环境下如何处理”吧!一、序言指令重排在单线程环境下有利于提...
    99+
    2023-06-30
  • Java指令重排序在多线程环境下的处理方法
    目录一、序言二、问题复原(一)关联变量1、结果预测2、指令重排(二)new创建对象1、解析创建过程2、重排序过程分析三、应对指令重排(一)AtomicReference原子类(二)v...
    99+
    2024-04-02
  • 怎么在java中使用volatile禁止指令重排
    怎么在java中使用volatile禁止指令重排?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用...
    99+
    2023-06-14
  • 怎么在Java中实现多线程排序
    这期内容当中小编将会给大家带来有关怎么在Java中实现多线程排序,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。java基本数据类型有哪些Java的基本数据类型分为:1、整数类型,用来表示整数的数据类型。2...
    99+
    2023-06-14
  • 怎么在Java中对多线程进行排序
    怎么在Java中对多线程进行排序?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象编程语言的代表,实现了面向...
    99+
    2023-06-14
  • linux环境下java中文乱码怎么解决
    部署在linux下的java应用程序中的中文会变成一个一个的“口”字,也就是乱码问题分析:代码中使用了如下的实现方式:new java.awt.Font("宋体", Font.PLAIN, 12)那么jdk中一定需要“宋体”这个字体($JA...
    99+
    2015-09-26
    linux java
  • java for循环内执行多线程问题怎么解决
    这篇文章主要介绍了java for循环内执行多线程问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇java for循环内执行多线程问题怎么解决文章都会有所收获,下面我们一起来看看吧...
    99+
    2023-07-05
  • Spring在多线程下@Resource注入为null怎么解决
    本篇内容主要讲解“Spring在多线程下@Resource注入为null怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring在多线程下@Resource注入为null怎么解决”吧!...
    99+
    2023-06-29
  • Java 内存模型与有序性:揭示多线程编程中的指令重排序行为
    1. Java 内存模型 (JMM) Java 内存模型 (JMM) 是 Java 虚拟机 (JVM) 对内存共享行为的抽象。它定义了多线程编程中变量之间的可见性和原子性。JMM 规定了线程对共享变量的写操作必须被其他线程立即看到,并...
    99+
    2024-02-04
    Java 内存模型 有序性 指令重排序 可见性 原子性
  • 如何深入理解Java多线程与并发框中重排序、屏障指令、as-if-serial规则
    这篇文章将为大家详细讲解有关如何深入理解Java多线程与并发框中重排序、屏障指令、as-if-serial规则,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。一、重排序前篇文章已经讲了Java...
    99+
    2023-06-05
  • Java多线程之线程安全问题怎么解决
    本篇内容主要讲解“Java多线程之线程安全问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java多线程之线程安全问题怎么解决”吧!1.线程安全概述1.1什么是线程安全问题首先我们需要...
    99+
    2023-06-30
  • Java自然语言处理:同步函数在多线程环境下的应用探讨
    随着大数据时代的到来,自然语言处理(NLP)技术得到了广泛的应用。而在实际应用中,NLP技术需要处理大量的数据,因此多线程技术的应用也变得尤为重要。在多线程环境下,同步函数的应用可以帮助我们保证数据的正确性,提高程序的效率。本文将会讨论J...
    99+
    2023-10-29
    自然语言处理 同步 函数
  • Java并发编程:如何在多线程环境下优雅地使用接口处理文件?
    在多线程环境下处理文件是一个常见的需求。Java提供了多种处理文件的API,例如File、BufferedReader、BufferedWriter等等。然而,在多线程环境下,使用这些API可能会导致线程安全问题。为了解决这个问题,我们可...
    99+
    2023-10-16
    并发 接口 文件
  • Java多线程死锁问题怎么解决
    解决Java多线程死锁问题的常用方法有以下几种:1. 避免使用多个锁:尽量减少使用多个锁来降低出现死锁的概率。2. 按照固定的顺序获...
    99+
    2023-09-22
    Java
  • java多线程内存泄漏怎么解决
    Java中的内存泄漏问题通常是由于没有正确释放对象所引用的资源而导致的。下面是一些解决内存泄漏问题的常见方法: 及时释放资源:在...
    99+
    2023-10-27
    java
  • Java 同步和 IDE 的奇妙冒险:如何在多线程环境下保证数据安全?
    在现代计算机系统中,多线程编程已成为不可避免的技术之一。但是,多线程编程对于程序员来说也带来了新的挑战,其中一个挑战就是如何在多线程环境下保证数据安全。Java 提供了一种机制来帮助解决这个问题,那就是同步。 Java 同步机制是一种基于...
    99+
    2023-06-26
    同步 ide http
  • java怎么使用多线程解决主线程提前结束问题
    这篇文章主要介绍“java怎么使用多线程解决主线程提前结束问题”,在日常操作中,相信很多人在java怎么使用多线程解决主线程提前结束问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java怎么使用多线程解决...
    99+
    2023-07-05
  • 解决在微服务环境下远程调用feign和异步线程存在请求数据丢失问题
    目录一、无异步线程得情况下feign远程调用:1、登录拦截器:2.问题示例图:3.解决方法:解决方式(高亮部分):从总线中获取request数据放入子线程中二、异步情况下丢失上下文问...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作