首页 > 编程语言 >Java-指令重排

Java-指令重排

时间:2023-12-08 11:55:20浏览次数:28  
标签:Singleton Java instance 指令 volatile 重排 线程

Java-指令重排

指令重排(Instruction Reordering)是指编译器或者处理器在不改变程序语义的前提下,重新安排指令的执行顺序,以优化性能或者满足硬件的执行特性。在多线程环境中,指令重排可能导致线程安全性问题,因为重排序可能改变原本按照程序顺序应该执行的操作次序。

单线程-可提高程序性能

在实际编程中,一般情况下我们不会故意去使用指令重排来提高性能,因为这可能导致程序出现难以预测和调试的问题。指令重排通常由编译器和硬件在保持程序语义不变的前提下进行优化。

然而,可以提供一个理论上可能利用指令重排来提高性能的示例。假设有以下的代码:

public class ReorderExample {
    private static int x = 0;
    private static boolean flag = false;

    public static void main(String[] args) throws InterruptedException {
        Thread writerThread = new Thread(() -> {
            x = 42;
            flag = true;
        });

        Thread readerThread = new Thread(() -> {
            if (flag) {
                System.out.println("x: " + x);
            }
        });

        writerThread.start();
        readerThread.start();

        writerThread.join();
        readerThread.join();
    }
}

在上述代码中,写入线程修改了 x​ 和 flag​ 两个变量,而读取线程在检查 flag​ 为 true​ 后打印 x​ 的值。在正常情况下,由于线程的交错执行,输出应该是 x: 42​。

然而,如果发生了指令重排,可能出现以下的情况:

  1. 写入线程重排了写入操作,先执行 flag = true​;
  2. 读取线程在检查 flag​ 为 true​ 后,输出 x​ 的值,此时 x​ 还没有被写入。

这样的重排可能导致输出为空,而不是预期的 x: 42​。然而,这种情况只是一个理论上的可能性,实际上并不鼓励使用这样的代码来尝试指令重排。在正常的应用程序中,我们更注重代码的可读性、可维护性和正确性,而不是依赖于指令重排来提高性能。

多线程-指令重排会破坏程序的正确性

Java中的指令重排问题通常与JVM和编译器有关。为了提高性能,JVM和编译器可能会对代码进行优化,包括指令重排。然而,在多线程环境中,这可能会破坏程序的正确性。

例子:

考虑以下的双重检查锁定(Double-Checked Locking)例子:

class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance <span style="font-weight: bold;" class="mark"> null) {      // 1. 第一次检查
            synchronized (Singleton.class) {
                if (instance </span> null) {  // 2. 第二次检查
                    instance = new Singleton();  // 3. 创建对象
                }
            }
        }
        return instance;  // 4. 返回对象引用
    }
}

在这个例子中,看起来是一个常见的双重检查锁定模式,但是在多线程环境下,由于指令重排,可能会导致问题。

如果指令重排发生,可能的执行顺序为:

  1. 线程1:检查 instance​ 不为null,进入同步块。
  2. 线程2:由于线程1还未完成创建对象,instance​ 仍为null,进入同步块。
  3. 线程2:创建对象。
  4. 线程2:将 instance​ 指向新创建的对象。
  5. 线程1:从同步块中退出,返回 instance​,但此时 instance​ 指向的对象可能还未完全初始化。

避免指令重排:

为了避免指令重排,可以使用volatile​关键字。在上述例子中,private static volatile Singleton instance;​ 中的 volatile​ 就是用来禁止指令重排的。

volatile​ 修饰的变量具有两个特性:

  1. 禁止指令重排。
  2. 强制将修改的值立即写入主内存,使得其他线程可以立即看到修改。

通过在 instance​ 上使用 volatile​,可以确保在对象引用被初始化后,其他线程能够正确地看到初始化的值。这是因为 volatile​ 关键字保证了在写入 instance​ 时,不会发生指令重排,从而保证了对象的安全发布。

标签:Singleton,Java,instance,指令,volatile,重排,线程
From: https://www.cnblogs.com/anhaoyang/p/javainstruction-resume-z2sq6bi.html

相关文章

  • Java-引用类型
    Java-引用类型四种引用类型(强引用、软引用、弱引用、虚引用)在Java中具有不同的使用场景,可以根据程序的需求和内存管理的要求来选择适当的引用类型。1.强引用(StrongReference):使用场景:在绝大多数情况下,我们使用的都是强引用。当一个对象具有强引用时,垃圾回收器不会回收该对......
  • java JSON对象与字符串间的转换
    importcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.JSONObject;//字符串转为JSON对象StringstrParam="{\"callerid\":\"013941128270\",\"timestart\":\"2021-07-2709:37:42\",\"status\"......
  • Java运算符
    1.运算符1.1算术运算符算术运算符是对数值型的变量进行运算publicclassOperator{publicstaticvoidmain(Stringargs[]){System.out.println(10/4);//2System.out.println(10.0/4);//2.5doubled=10/4;System.out.println(......
  • java 正则表达式 用法
    在一个复杂的字符串中,使用正则表达式来取其中某个值importjava.util.regex.*;//正则表达式引用//复杂的字符串Stringinput="{\"pbxToken\":\"1ja930jsdlij912h94hk5l35poeweer\"}"+"{\"LS_CallStatus_Event_Type\":\"\",\"callId......
  • JavaWeb - Day03 - Ajax、前端工程化、Element
    01.Ajax-介绍Ajax概念:AsynchronousJavaScriptAndXML,异步的JavaScript和XML。作用:数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据。异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用的校验等等......
  • Java第五课_函数重载递归和初识数组
    1.函数重载//关键字:public,static等//保留字:关键字的预备役var,goto//jdk11开始,还有JS里var升级为关键字:var变量名=初始值;//重载/overload:在同一个类中,允许函数重名,但是他们的参数列表必须不同.......
  • 前端学习-JavaScript学习-js基础-API02
    学习视频:黑马程序员视频链接事件监听三要素:事件源、事件类型、事件处理程序随机点名案例<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"&......
  • Java 读取EXCEL表格中的数据,将数据转为SQL语句
    **[参考文档](https://blog.csdn.net/wl_Honest/article/details/83985751?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_utm_term~default-0-83985751-blog-81103171.pc_relevant_paycolumn_v3&spm=1001.2101.3001.4242.1&utm_relevant_index=3)......
  • Java登陆第二十天——HTML常用标签
    文本标签文本常用的HTML标签:标签名标签描述<h1></h1>标题标签<h6></h6>标题标签<p></p>段落标签<hr>换行标签<br>换行标签标签栗子:<!DOCTYPEhtml><htmllang="en"><head><metacharset=&quo......
  • 4 种方法,帮你快速新建 Java 项目!
    大家好,我是鱼皮。今天给大家分享常用的快速初始化Java项目的几种方法。比较全面,有一些方法你可能并不知道,但如果都掌握的话,基本上够用一辈子了哈哈。如何快速初始化Java项目?1、使用开发工具Java开发者最常用的开发工具当属JetBrainsIDEA了!IDEA不仅功能完善、插件丰富,而且......