当前位置: 首页 > news >正文

只能用域名访问WordPress博客seo教程

只能用域名访问WordPress,博客seo教程,十堰seo优化方法,小程序商城怎么弄0.引言 理解 JMM (Java Memory Model - JMM) 是掌握 Java 并发编程的关键,它定义了多线程环境下,线程如何与主内存以及彼此之间交互内存数据。 核心目标: JMM 旨在解决多线程编程中的三个核心问题: 原子性 (Atomicity)&#xf…

0.引言

理解 JMM (Java Memory Model - JMM) 是掌握 Java 并发编程的关键,它定义了多线程环境下,线程如何与主内存以及彼此之间交互内存数据。

核心目标: JMM 旨在解决多线程编程中的三个核心问题:

  1. 原子性 (Atomicity): 一个操作是不可中断的,要么全部执行成功,要么完全不执行。
  2. 可见性 (Visibility): 一个线程修改了共享变量的值,其他线程能够立即得知这个修改。
  3. 有序性 (Ordering): 程序执行的顺序可能和代码编写的顺序不一致(指令重排序),JMM 定义了在何种情况下这种重排序是被允许或禁止的。

1.第一层:浅显易懂 - 为什么需要 JMM? (The Problem)

想象一下一个简单的场景:

public class VisibilityProblem {private static boolean flag = false; // 共享变量private static int value = 0;        // 共享变量public static void main(String[] args) {// 线程 Anew Thread(() -> {while (!flag) { // 循环检查 flag// 空循环,等待 flag 变为 true}System.out.println("Value: " + value); // 打印 value}).start();// 线程 Bnew Thread(() -> {value = 42;   // 步骤 1:设置 valueflag = true;  // 步骤 2:设置 flag}).start();}
}
  • 直觉期望: 线程 B 先设置 value = 42,然后设置 flag = true。线程 A 看到 flag 变为 true 后跳出循环,打印出 Value: 42
  • 现实问题:
    • 可见性问题: 线程 B 修改了 flagvalue,但这些修改可能只存在于线程 B 的 CPU 缓存或寄存器中,没有立即写回主内存。线程 A 在自己的缓存中看到的 flag 可能仍然是 false,导致它永远无法跳出循环。即使跳出了循环,它看到的 value 也可能是 0 而不是 42
    • 有序性问题: 编译器或处理器为了优化性能,可能会对指令进行重排序。线程 B 中的 flag = true 操作可能在 value = 42 之前执行。如果此时线程 A 看到了 flagtrue 而跳出循环,它看到的 value 就可能是未初始化的 0

JMM 就是为了解决这类在多线程环境下因缓存、指令重排序等优化带来的不可预测行为而制定的规则。


2.第二层:核心概念 - JMM 的抽象模型 (The Abstraction)

JMM 定义了一个抽象的内存模型,它屏蔽了底层硬件的具体实现细节(如 CPU 缓存、缓存一致性协议),为 Java 程序员提供了一个统一的视图:

  1. 主内存 (Main Memory):
    • 存储所有共享变量(实例字段、静态字段、数组元素)的原始值。
    • 是线程间共享的区域。
  2. 工作内存 (Working Memory / Local Memory):
    • 每个线程都有自己的工作内存。
    • 存储该线程使用到的共享变量的副本
    • 线程对共享变量的所有操作(读取、赋值等)都必须在工作内存中进行,不能直接读写主内存
    • 工作内存是 JMM 的一个抽象概念,它涵盖了 CPU 寄存器、各级缓存、写缓冲区等硬件优化。

内存交互操作 (8 种原子操作)

JMM 定义了 8 种原子操作来描述线程、工作内存和主内存之间的交互:

  • lock (锁定):作用于主内存变量,标识其为线程独占状态。
  • unlock (解锁):作用于主内存变量,释放锁定状态。
  • read (读取):作用于主内存变量,将变量值从主内存传输到线程的工作内存。
  • load (载入):作用于工作内存变量,将 read 操作得到的值放入工作内存的变量副本中。
  • use (使用):作用于工作内存变量,将变量值传递给执行引擎(如进行计算)。
  • assign (赋值):作用于工作内存变量,将执行引擎接收到的值赋给工作内存变量。
  • store (存储):作用于工作内存变量,将变量值从工作内存传输到主内存。
  • write (写入):作用于主内存变量,将 store 操作传输过来的值放入主内存变量中。

规则: JMM 规定这些操作必须满足特定的顺序和约束(如 readloadstorewrite 必须成对按顺序出现),但允许在成对操作之间插入其他操作(这是导致可见性和有序性问题的根源之一)。更关键的规则体现在 happens-before 原则上。


3.第三层:关键机制 - Happens-Before (HB)

happens-before 是 JMM 的核心概念,它定义了两个操作之间的偏序关系。如果操作 A happens-before 操作 B,那么:

  1. 可见性保证: A 对共享变量的修改(结果)一定对 B 可见。
  2. 有序性保证: A 在程序顺序上一定排在 B 之前执行(禁止某些重排序)。

注意: happens-before 并不一定意味着时间上的先后!它强调的是可见性和顺序的保证。如果两个操作之间没有 happens-before 关系,JVM 可以随意对它们进行重排序。

3.1JMM 定义的天然 Happens-Before 规则

  1. 程序次序规则 (Program Order Rule):同一个线程中,按照控制流顺序(可能是分支、循环等),前面的操作 happens-before 后面的操作。
  2. 管程锁定规则 (Monitor Lock Rule): 一个 unlock 操作 happens-before 于后续对同一个锁lock 操作。
  3. volatile 变量规则 (Volatile Variable Rule): 对一个 volatile 变量的写操作 happens-before 于后续对这个变量的读操作。
  4. 线程启动规则 (Thread Start Rule): Thread.start() 调用 happens-before 于被启动线程中的任何操作。
  5. 线程终止规则 (Thread Termination Rule): 线程中的所有操作都 happens-before 于其他线程检测到该线程已经终止(如 Thread.join() 返回成功或 Thread.isAlive() 返回 false)。
  6. 线程中断规则 (Thread Interruption Rule): 对线程 interrupt() 的调用 happens-before 于被中断线程检测到中断事件(抛出 InterruptedException 或调用 isInterrupted()/interrupted())。
  7. 对象终结规则 (Finalizer Rule): 一个对象的初始化完成(构造函数执行结束)happens-before 于它的 finalize() 方法的开始。
  8. 传递性 (Transitivity): 如果 A happens-before B,且 B happens-before C,那么 A happens-before C。

happens-before 的意义: 程序员只需要利用这些规则(主要是通过 synchronizedvolatilefinal 等关键字以及 java.util.concurrent 包中的工具),就能确保多线程操作的可见性和有序性,无需关心底层复杂的缓存和重排序细节。


4.第四层:深入剖析 - volatile 关键字

volatile 是 JMM 中最重要的关键字之一,它提供了比 synchronized 更轻量级的同步机制。

4.1volatile 的语义

  1. 保证可见性:
    • 对一个 volatile 变量的写操作,会立即刷新到主内存
    • 对一个 volatile 变量的读操作,会从主内存中读取最新的值(或保证看到最近写入的值)。
    • 这通过禁止编译器/处理器对 volatile 变量的读写操作进行缓存优化来实现。
  2. 禁止指令重排序 (部分):
    • 编译器在生成字节码时,会在 volatile 写操作前后插入写屏障 (StoreStore + StoreLoad)
    • volatile 读操作前后插入读屏障 (LoadLoad + LoadStore)
    • 写屏障 (Store Barrier):
      • StoreStore: 确保在该屏障之前的所有普通写操作都刷新到主内存(对其他线程可见)。
      • StoreLoad: 确保在该屏障之前volatile 写操作都完成,并且刷新到主内存后,才能执行该屏障之后volatile 读/写操作(开销较大,通常由 StoreLoad 承担)。
    • 读屏障 (Load Barrier):
      • LoadLoad: 确保在该屏障之后的所有操作(普通读或 volatile 读)都在该屏障之后的读操作之前执行(禁止重排序),并且强制从主内存或最新缓存中加载数据。
      • LoadStore: 确保在该屏障之后的所有操作都在该屏障之后的写操作之前执行(禁止重排序),并且这些写操作的数据依赖在该屏障之前的读操作已完成。
    • 这些屏障共同作用,确保了 volatile 变量读写操作相对于其前后代码的相对顺序,从而实现了 happens-before 规则中的有序性保证。

4.2volatile 的局限性

  • 不保证原子性: volatile 不能保证复合操作的原子性。例如 volatile int count; count++; 这个操作 (count++ 包含读-改-写三步) 在多线程下仍然是不安全的。需要使用 synchronizedAtomicInteger 等。

4.3volatile 的典型用法

  • 状态标志位: 如开头的例子,用 volatile boolean flag; 来安全地通知其他线程状态改变。
  • 一次性安全发布 (One-Time Safe Publication): 利用 volatile 写操作的 StoreStore 屏障,确保在发布对象引用之前,对象的初始化已经完全完成(构造函数结束)。
    public class Singleton {private static volatile Singleton instance; // volatile 保证安全发布private Singleton() {}public static Singleton getInstance() {if (instance == null) { // 第一次检查 (无锁)synchronized (Singleton.class) {if (instance == null) { // 第二次检查 (加锁)instance = new Singleton(); // volatile 写}}}return instance;}
    }
    
    如果没有 volatile,其他线程可能看到一个未初始化完成Singleton 对象(指令重排序导致引用赋值在构造函数完成之前发生)。
  • 独立观察 (Independent Observation): 定期发布观察结果供其他程序使用。
  • 开销较低的读-写锁策略: 当读远多于写时,可以用 volatile 保证写操作的可见性,读操作不需要加锁(但写操作需要额外的同步机制如 synchronized 或 CAS 来保证原子性)。

5.第五层:JMM 与并发编程实践

理解 JMM 对于编写正确、高效、可预测的并发程序至关重要:

  1. 优先使用高级并发工具: java.util.concurrent 包 (ConcurrentHashMap, ExecutorService, CountDownLatch, CyclicBarrier, AtomicXxx 类等) 是构建在 JMM 基础之上的,它们通常比直接使用 synchronizedvolatile 更安全、更高效、更易用。理解 JMM 能让你更好地理解和使用这些工具。
  2. 正确使用 synchronized: synchronized 块不仅提供互斥(原子性),也提供强大的内存语义:进入 synchronized 块(获得锁)相当于执行一个 volatile 操作(能看到之前持有该锁的线程的所有修改),退出 synchronized 块(释放锁)相当于执行一个 volatile 操作(将修改刷新到主内存)。这确保了临界区内外操作的可见性和有序性。
  3. 理解 final 字段:final 修饰的字段在构造函数中初始化后,其值对其他线程是可见的(无需同步),前提是对象的引用本身是正确发布的(例如通过 volatilesynchronized 安全发布规则)。这是 JMM 对 final 的特殊保证。
  4. 避免过度同步: 不必要的同步会带来性能开销。理解 JMM 可以帮助你判断何时需要同步(主要是为了保护共享可变状态),何时可以避免。
  5. 警惕内存可见性导致的微妙 Bug: 很多并发 Bug 不是由竞态条件引起的,而是由内存可见性问题引起的。理解 JMM 是诊断这类 Bug 的基础。

6.总结

  • JMM 是什么? 一个规范,定义了多线程环境下 Java 程序如何与内存交互,确保程序在并发执行时的可见性有序性(以及通过其他机制如锁保证的原子性)。
  • 核心问题: 解决因 CPU 缓存、指令重排序导致的可见性有序性问题。
  • 抽象模型: 主内存(共享)和工作内存(线程私有副本),定义了 8 种内存交互操作。
  • 核心机制: happens-before 关系。它定义了操作间的可见性和顺序保证。JMM 定义了一系列天然规则(程序次序、锁、volatile、线程启动/终止等)。
  • volatile 关键字:
    • 保证可见性(写立即刷新,读获取最新值)。
    • 通过内存屏障StoreStore, StoreLoad, LoadLoad, LoadStore禁止特定类型的指令重排序
    • 不保证原子性
  • 实践意义: 理解 JMM 是编写正确、高效并发 Java 程序的基础。它解释了高级并发工具的工作原理,指导你正确使用 synchronizedvolatilefinal,并帮助你诊断复杂的并发 Bug。

掌握 JMM 需要时间和实践。从理解基本问题和抽象模型开始,逐步深入到 happens-beforevolatile 的细节,最终将其应用于并发编程实践中,是学习 JMM 的有效路径。

http://www.hkea.cn/news/506034/

相关文章:

  • 利用vps做网站关键字排名查询
  • 常熟网站制作找哪家好品牌型网站制作价格
  • 怎么做自己网站推广网络广告
  • 化州网站建设促销方法100种
  • 长沙专业网站设计平台新闻最新消息10条
  • 惠州网站建设制作宣传推广方案
  • 宁波网站推广外包服务长岭网站优化公司
  • 哈尔滨市哪里做淘宝网站seo课程心得体会
  • 做网站建设公司企业一个企业该如何进行网络营销
  • 移动端h5网站开发服务企业seo推广
  • 管理公司网站建设引擎搜索优化
  • 上市公司专利查询网站百度广告投放价格
  • html5电商网页制作网站怎么seo关键词排名优化推广
  • 大同网站建设黄冈网站推广优化找哪家
  • 昌邑网站建设站长之家网站排名
  • 建设企业网站的需求分析免费域名
  • 重庆欧勒精细有限公司网站策划书百度竞价推广开户
  • 怎么做一键添加信任网站ios aso优化工具
  • ps做网站的分辨率多少钱苹果cms永久免费建站程序
  • 网站推广积分常用于网站推广的营销手段是
  • wordpress时间云储存沈阳网站制作优化推广
  • h5响应式网站建设竞价托管哪家效果好
  • 企业解决方案参考网站品牌软文营销案例
  • 做淘客要有好的网站上海百度seo
  • 网站建设 seojsc宁德seo推广
  • 建立网站的作用信息流优化师工作总结
  • 如何建设物流网站近期时事新闻
  • 网站开发大赛发言稿网址搜索
  • 论坛类型的网站怎么做拉新推广平台有哪些
  • pc官方网站视频专用客户端app