美文网首页
JVM的线程安全

JVM的线程安全

作者: 自天佑之吉无不利 | 来源:发表于2023-10-15 20:32 被阅读0次

在编程过程中,你有没有遇到过在运行多线程程序时想用共享变量来通讯,却发现程序结果和预期不一致的情况?这个常见的问题就是多线程编程的难点,涉及内存可见性和重排等问题。

可见性问题

第一个问题出现在处理器和内存之间。现代电脑系统中,处理器速度很快,内存的读写速度却远远不能比肩。为了解决这种矛盾,引入了高速缓存,处理器将计算所需数据复制到缓存,从而加快运算速度。然而,这也引发了缓存的一致性问题,也就是说,在多处理器系统里,如果每个处理器都同时使用相同的内存,那么它们的缓存数据可能会出现差异。

处理器必须按照一些协议进行同步操作,在读写时维持缓存一致性。这里就涉及到内存可见性问题,也就是一个线程修改的状态能够即时在其他线程中可见。

重排问题

我们日常写的代码,在实际运行之前,都会经过 JVM 及底层 CPU 等各种优化,来达到最优的执行性能。但是这种优化都是基于单线程考虑的优化,如果你的程序是以多线程的方式运行,反而很容易引发各种问题。所以对于多线程的程序,知道 JVM 实际进行了哪些优化非常重要。

指令序列从源代码到实际执行的过程可能会经历以下三种重新排序。

编译器优化的重排

JVM 的编译器有可能在保持单线程原有含义的同时,对代码的运作流程进行修正,从而提升运行效率。

指令并行的重排

指令并行重排属于 CPU 优化的范畴,对于不存在数据前后依赖的情况,CPU 可能会调整指令的执行,将多条指令重叠执行。

内存系统的重排

因为处理器利用了缓存以及读写缓冲区,所以负载和保存的任务有可能会混乱地进行。这种重新排序可能会使内存与缓存数据同步时间产生偏差。

JMM
Java 内存模型是为了解决这些问题而设计的线程安全的解决方案。它是 JVM 提供的一种抽象概念,描述了多线程之间如何协同工作以及如何访问和改变共享数据。它定义了 Java 程序和虚拟机之间的互动规则,确保程序在多线程环境下具有一致的内存可见性和操作顺序。

JMM 也提供了一些实现这个规则的解决方案。

  • Synchronized 关键字:Java 语言中最基本的同步手段,它可以保证同一时刻只有一个线程会执行临界区内的代码,从而避免了多线程访问共享资源的情况。
  • Volatile 关键字:保证变量的可见性和有序性。当一个变量被 Volatile 修饰的时候,修改变量的值会立即被其他线程看见,同时编译器和处理器不会把其指令重排到其他语句之前或之后。
  • final 关键字:保证被修饰的变量的值只能被赋值一次,也就是说它是一个常量,一旦被赋值后不可修改。
  • Lock 接口:JDK5 提供的一种高级的同步手段,它和 Synchronized 关键字不同,它可以重入,也就是同一个线程可以多次获取同一个锁。
  • 原子变量:保证在多线程环境下,对于变量的增删改操作是原子性的。

可见性就是指在一个线程中,共享变量的修改在另一个线程中不能被看到。这主要是由于处理器和内存的速度不同导致的,处理器会把计算所需的数据复制到缓存里,从而产生了缓存一致性问题。为了解决这个问题,线程必须按照一些协议进行同步操作,保证修改的状态能够即时在其他线程中可见。

重排问题是指在翻译器和数据处理器执行代码的时候,对命令顺序执行的再次排列。这种优化是为了提高程序的执行性能,但是在多线程环境下可能导致程序的执行结果不符合预期。为了解决重排问题,Java 内存模型规定了一些规则,如读取和载入操作必须按顺序执行,存储和写入操作也必须按顺序执行等。

Java 提供了一些策略来应对可见性和重排的问题。其中,Synchronized 关键字能确保在同一时间段内只有一个线程能够执行临界区域的代码,从而防止多线程共享资源的情况发生。Volatile 关键字可以保证变量的可见性和有序性。Lock 接口和原子变量也可以提供线程安全的解决方案。此外 final 关键字可以保证被修饰的变量的值只能被赋值一,不可修改。所以说,熟练掌握 JMM 是写出线程安全的 Java 程序的基础。

此文章为10月Day10学习笔记,内容来源于极客时间《云时代JVM实战 》,强烈推荐该课程

相关文章

  • 深入JVM内核原理-4.JVM锁

    1.JVM锁概要 JVM锁概要.png 2.线程安全 JVM线程安全1.pngJVM线程安全2.png 3.对象头...

  • 高效并发

    从JVM的角度看一下Java与线程,内存模型,线程安全以及JVM对于锁的优化 硬件内存模型与JVM内存模型 硬件的...

  • 深入理解JVM(第二章笔记)

    JVM内存区域 jvm 按照线程安全进行分类:线程私有: 程序计数器,Java虚拟机栈,本地方法栈线程共享: Ja...

  • 关于绝对线程安全和相对线程安全的思考

    Brian Goetz的《Java并发编程实战》有对线程安全的定义: 周志明在《深入理解JVM》中认为上述线程安全...

  • MM 小册子

    hashmap和hashtable区别线程安全,非线程安全 为什么产生死锁相互占有对方需要争夺的资源 jvm类加载...

  • 分布式锁都有哪些实现方案?

    一、业务场景 同一个jvm里多个线程操作同一个有状态的变量,可以通过JVM内的锁保证线程安全。 如果是多个JVM操...

  • 深入JVM内核7 锁

    深入JVM内核 目录 1. 线程安全 多线程网站统计访问人数使用锁,维护计数器的串行访问与安全性 多线程访问Arr...

  • JVM之线程安全

    并发问题 在了解了JVM结构,特别是内存结构后,我们再说说并发问题产生的原因。在上面的内容中我们分析了Java堆、...

  • 深入理解JVM第十三章笔记

    深入理解JVM第十三章笔记 线程安全 对“线程安全”一个比较准确的定义: 当多个线程访问同一个对象时,如果不用考虑...

  • 从JMM引申到线程安全

    1、世界存在线程安全问题2、提出JMM规范3、JVM实现参考JMM,解决线程安全问题 JMM定义屏蔽掉各种硬件和操...

网友评论

      本文标题:JVM的线程安全

      本文链接:https://www.haomeiwen.com/subject/peatidtx.html