JMM

Java内存模型是定义程序中各个变量的访问规则,包括了实例字段,静态字段,数组对象等。不含有局部变量及方法参数。

Java内存模型规定了全部变量都记录在主内存,每条线程还有自己的工作内存。线程对变量的读写只能在工作内存中。

对于不同内存之间的操作,Java模型仅规定了read,load,store,write的顺序,而这些指令中可以插入别的指令。

volatile在各个线程的工作内存中不存在一致性问题,因为读写时均会刷新,但是Java的运算并非是原子操作,以及有指令重排等,故在并发情况时不是安全的。volatile不能同步的本质就是指令重排。

在并发时,volatile的同步性能确实优先于synchronized以及concurrent,但是由于虚机会对所做许多消除及优化,且volatile非常难于控制,故选择volatile的情况仅是一些语义的需求。

Java的read,load,store,write均是原子性的,故基本数据类型也是原子性的,当然有long,double的非原子协定。

Java提供了volatile与synchronized保证线程之间操作的有序性。volatile本身就有禁止指令重排的语义。

Java1.5以后内存模型被修正,Immutable的对象一定是线程安全的。(String,被final修饰的对象)

Java中如Vector等线程安全的容器,它的add,get等方法均是被synchronized修饰的。但是它不是绝对线程安全的,因为可以在getSize以后去减少当中某一个元素,再去读这个元素,就会发生异常。因此Vector,hashTable等时相对线程安全的。

 

互斥同步:

同步时指多个线程在并发访问共享数据时,保证共享数据在同一个时刻只能被一个(一些,若是信号量)线程使用。互斥是同步的手段,临界区(Critical Section),互斥量(Mutex),信号量(Semaphore)都是互斥的实现方式。故互斥是因,同步是果。

Java的线程是映射到操作系统原生线程之上的,当阻塞或唤醒一个线程时,均是操作系统介入,故需从用户态转换到核心态中。因为该转换需耗费较多处理机时间,故synchronized非常耗时,而虚机优化时会做自旋操作,避免频繁切入核心态。

 

JIT(Just In TimeCompiler)即时编译器,当虚拟机发现部分代码频繁时,会将之认为是hot spot code,并编译为本地平台相关的机器码。

 

编译器优化技术:公共子表达式消除;数组范围检查消除;方法内联;逃逸分析;表数内逃

逃逸分析:分析对象的动态作用域;当一个对象在方法中被定义以后,它有可能被外部方法引用,称为方法逃逸;被外部线程访问,称为线程逃逸。

若能证明一个对象不会逃逸到方法及线程之外,可以为这个对象做 栈上分配以减少回收时间。同时若该对象不会逃逸出线程,就不会出现同步问题,可以做 同步消除

Java较C慢在:JIT不能使用大规模的优化以避免代码跑的慢,Java的动态性决定了Java必须做安全性检查,同时编译器不能窥见代码全貌,不能有效调优。Java有GC回收等。

 

通过Java提供的"Unreachable code"可以实现C语言中的条件编译(指定Ture,False)。

编译器会对代码进行优化,对于条件永远为false的语句,JAVA编译器将不会对其生成字节码。

Java的reference可能是32也可能是64,64位的数据类型只有long与double,在32位系统中,long与double的赋值不能保证线程同步。故二者需以volatile修饰。

volatile本身不保证获取和设置的原子操作性,仅保持修改的可见性。

 

Java语言规范规定了JVM线程内部维持顺序化语义,也就是说只要程序的最终结果等同于它在严格的顺序化环境下的结果,那么指令的执行顺序就可能与代码的顺序不一致。这个过程通过叫做指令的重排序。

 

JMM会被归纳为有三个特性:原子性、可见性、有序性。JMM中的操作有如下8种,分别是read、load、use、assign、store、write以及lock和unlock。

Java内存模型具备一些先天的“有序性”,即不需要通过任何手段就能够得到保证的有序性,这个通常也称为 happens-before 原则。如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序。

happens-before就是JMM的先天有序性。(lock,start,interrupt,finalizer)

### JMM 的基本概念 Java 内存模型(JMM, Java Memory Model)是 Java 虚拟机的一部分,用于定义多线程程序在共享内存中的交互规则。它的核心目标在于为线程间操作提供一致的行为规范,确保多线程环境下数据的一致性可见性[^1]。 JMM 不仅是一个抽象的概念框架,还涉及具体的实现细节,比如如何利用硬件特性(如缓存一致性协议、内存屏障等),从而保障多线程程序的正确运行[^2]。 --- ### JMM 的主要原理 #### 1. **内存分区结构** JMM 定义了一个抽象的内存结构,其中主要包括主内存(Main Memory)工作内存(Working Memory)。 - 主内存存储的是实例对象及其字段的实际值。 - 工作内存则是每个线程私有的区域,保存该线程使用的变量副本。当线程读取某个变量时,会先从主内存加载到自己的工作内存;写入时,则需将更新后的值刷新回主内存[^3]。 这种设计使得不同线程之间无法直接访问彼此的工作内存,而必须通过主内存进行通信。 #### 2. **三大特性** ##### (1) **原子性** 指不可分割的操作,在同一时刻只能由一个线程完成。然而需要注意的是,某些看似简单的操作可能并非真正意义上的原子操作。例如 `i++` 实际上包含了三个步骤:读取 i 的当前值、计算新值并将其写回。如果多个线程同时执行此语句,就可能出现竞态条件[^4]。 为了保证复杂操作的原子性,通常借助锁机制(如 synchronized 或 ReentrantLock)或者无锁算法(如 CAS 循环比较交换技术)来实现。 ##### (2) **可见性** 指的是当一个线程修改了某共享变量后,其他线程能够立即感知这一变化的能力。由于现代计算机体系架构中存在高速缓存层,可能导致最近一次更改尚未同步至主存便被另一个 CPU 核心所获取的情况发生。为此,JMM 提供了一些关键字支持,像 volatile 就是用来强制指定每次对该标记位属性的访问都必须直接作用于主存之上,而不是依赖本地拷贝版本。 ##### (3) **有序性** 即使源码层面按照既定顺序书写逻辑流程,但在实际编译优化过程中仍可能发生指令重排现象——即调整原本应该遵循先后次序的动作序列以便提升效率。不过这往往会造成意想不到的结果特别是在跨线程协作场景下尤为明显。因此引入 happens-before 关系作为约束手段之一,明确规定哪些情形之下允许打破常规排列规律而不影响最终效果评估标准。 以下是几个典型的 happens-before 规则: - 程序顺序规则:单一线程内的动作保持原有声明位置关系; - 监视器锁定规则:解锁前发生的事件必定早于后续加锁行为之前; - Volatile 变量规则:针对同一个 volatile 类型成员项而言,前面对其所做的任何改动必然优先反映给后来查询者看到的内容; - 线程启动/终止规则:新建子进程正式投入运转之后才能看见父进程中已完成初始化部分的状态设定情况同样适用于结束阶段处理完毕信号传递过程等等。 --- ### 示例代码展示 下面给出一段简单示例演示上述理论知识点的应用: ```java public class VisibilityExample { private static boolean ready; private static int number; public static void main(String[] args) throws InterruptedException { new Thread(() -> { while (!ready); // spin-wait until flag is set to true by another thread. System.out.println("Number: " + number); }).start(); Thread.sleep(100); number = 42; // Write operation on shared variable 'number'. ready = true; // Set the readiness indicator which should be visible across threads. /* Without proper synchronization or using a memory barrier such as declaring 'ready' as volatile, there's no guarantee that changes made here will become immediately apparent elsewhere */ } } ``` 在此例子当中如果没有采用适当措施的话很可能造成输出结果不符合预期因为第二个线程未必能及时察觉第一个线程已经改变了相应数值状态。 --- ### 总结 综上所述,深入理解 JMM 对开发人员来说非常重要,尤其是在构建高性能并发应用程序的时候。掌握好其背后的运作机理有助于我们更好地规避潜在风险点进而提高整体软件质量水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值