首页 > 编程语言 >Java中指令重排在多线程中出现数据错误的例子

Java中指令重排在多线程中出现数据错误的例子

时间:2022-11-13 23:33:19浏览次数:48  
标签:Java reValue flag 指令 线程 重排 多线程

概述

听说当两条指令互相不依赖的时候,在cpu或者jvm那儿可能会为了提高性能而进行指令重排。

数据依赖

比如下面两条代码就没有数据依赖:

int  a = 5;

int  b= 2;

这两条指令先后顺序并不影响程序运行逻辑,重排也是是没有问题的。

多线程

但是,听说在多线程的时候就会出现问题,因为单个线程有依赖可以检测出来。

多个线程操作同一个对象的时候,因为每个线程都有自己的工作区,主存与工作内存交互不及时,就会导致数据出问题。

来个例子:

代码分析:

/**
     * 理论上来说:
     * 1.线程1先执行完,线程2开始执行
     *          a=1;
     *          flag=true;
     *          if (flag) {
     *                     a = a + 5;
     *                     System.out.println("reValue:" + a);
     *                 }
     *  运行结果是:输出reValue:6
     *
     *  2.线程1先执行一半,线程2执行
     *          a=1;
     *          if (flag) {
     *             a = a + 5;
     *             System.out.println("reValue:" + a);
     *          }
     *          flag=true;
     *  运行结果:无。
     *
     * 3.线程2先执行,线程1开始执行
     *          if (flag) {
     *                     a = a + 5;
     *                     System.out.println("reValue:" + a);
     *                 }
     *          a=1;
     *          flag=true;
     *  运行结果是:无。
     *
     * 如果在线程1中发生指令重排!!!!!
     * 就会出现:
     * 线程1先执行一半,线程2执行
     *          flag=true;
     *          if (flag) {
     *             a = a + 5;
     *             System.out.println("reValue:" + a);
     *          }
     *          a=1;
     * 运行结果:控制台输出reValue:a
     */
点击查看

运行结果:

 

实不相瞒,秉持着实事求是的原则,不经历过的我不信。

我i5第十二代处理器,运行了一晚上,只出了这一次指令重排。它真的,我哭死。

还好运行出来一次,我勉强信了。

总结

它如何产生:

就是因为每个线程都有自己的工作内存,而工作内存与主内存交互不够及时呗。

 

 

它如何解决:

当你觉得某个变量会因为指令重排而导致线程不安全,那么对其使用volatile的声明,它使得变量及时地在主存中更新 :

1、对volatile变量的写会立即刷新到主存
2、对volatile变量的读会读主存中的新值

标签:Java,reValue,flag,指令,线程,重排,多线程
From: https://www.cnblogs.com/lurenjia-bky/p/16886709.html

相关文章

  • java时间工具类
    packagecom.example.httpdemo2.utils;importjava.text.DateFormat;importjava.text.ParseException;importjava.text.SimpleDateFormat;importjava.util.ArrayLi......
  • java——继承与多态——final关键字001
    final关键字概念与四种用法:          final关键字用于修饰类:             final关键字用于修饰成员方法:   ......
  • Java 序列化与反序列化
    (目录)一、说明序列化与反序列化是什么序列化:将Java对象表示为一个字节序列,存储对象数据到文件中,可用于网络传输反序列化:从文件中读取序列化对象,对它进行反序列化,恢......
  • Javascript的预解析
    浏览器不是直接运行JS的,是调用js引擎运行js.js引擎运行js分为两个步骤:1.预解析:js引擎会把js里面所有的var,以及所有的function提升到当前作用域的最前面2.代码执行......
  • Head First Java 读书笔记 15章
    第15章:网络与线程(网络联机)在Java中,所有网络运作的低层细节都已经由java.net函数库处理。Java中,传送和接收网络上的数据,是在链接上使用不同链接串流的输入和输出。什么......
  • Java开发学习(四十一)----MyBatisPlus标准数据层(增删查改分页)开发
    一、标准CRUD使用对于标准的CRUD功能都有哪些以及MyBatisPlus都提供了哪些方法可以使用呢?我们先来看张图:1.1环境准备这里用的环境就是Java开发学习(四十)----MyBat......
  • java
    可变参数在方法声明中,在指定参数类型后加一个省略号(...)一个方法中只能指定一个可变参数,它必须是方法的最后一个参数,任何普通的参数必须唉它之前声明    ......
  • 【Java】回顾一下Java中的synchronized
    synchronized在JDK1.5之前是一个重量级锁,相当于JUC里面的lock锁,但是在1.6版本及之后对它做了很大的升级和优化,它不在那么的笨重了。synchronized的作用主要有三个:原子性:确......
  • 读者-写者(多线程)
     一、同步互斥问题-读者写者问题之写者优先(一)问题要求抽象解释:多个进程访问一个共享的数据区读者(读进程)只能读数据,写者(写进程)只能写数据适用于数据库、文件、内存......
  • 读者-写者(多线程)
    读者-写者(多线程)0推荐在openEuer上实现1描述操作系统中“读者-写者”问题,理解问题的本质,提交你理解或查找到的文本资料2利用多线程完成reader和writer3在main中测......