💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## java内存模型 ![](https://img.kancloud.cn/93/74/93745502f796d301067e393655147067_562x362.png) 主内存 * 主要存储变量(包括。实例字段,静态字段和构成对象的元素) * 对应Java内存中的堆 工作内存 * 每个线程都有自己的工作内存,存储了对应的引用,方法参数。 * 对应Java虚拟机的栈 ## 八种原子操作 ![](https://img.kancloud.cn/39/c0/39c0667c421349a4216442775a0ac342_742x582.png) ### 从主内存的读取数据到线程的私有内存中 * unlock:作用于主内存的变量。它把一个处于锁定状态的变量释放出来,释放后的变量才能被其他线程访问。 * read:作用于主内存的变量(跨读)。它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。 * load:作用于工作内存的变量(写)。它把read操作从主内存中得到的变量值放入到工作内存变量副本中。 * use:作用于工作内存的变量。它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个\*\*需要使用到变量的值的字节码指令时(代码的读值操作)\*\*会执行这个操作。 ### 从线程的私有内存数据同步到主内存中 * assign:作用于工作内存的变量。它把一个从执行引擎收到的值赋给工作内存的变量,每当虚拟机遇到\*\*给变量赋值的字节码指令时(代码的赋值操作)\*\*会执行这个操作 * store:作用于工作内存的变量(跨读)。它把工作内存中一个变量值传送到主内存中。以便随后的write操作。 * write:作用于主内存的变量(写)。它把store操作从工作内存中得到的变量的值,放入主内存的变量中 * lock:作用于主内存的变量。它把一个变量标识为一条线程独占的状态 java为了**保证数据在****单线程****情形下传输过程中的准确性与数据一致性**,规定了内存之间交互的一些操作规则 * 一个新的变量只能在主内存中诞生,工作内存要使用或者赋值。必须要经过load或assign操作。 * 不允许read和load、store和write操作之一单独出现。即不允许一个变量从主内存读取了但工作内存不接受。或者从工作内存发起回写了但主内存不接受的情况 * 不允许一个线程丢弃它的最近的assign操作。即变量在工作内存改变了后必须把该变化同步到主内存中。 * 不允许没有发生任何的assign操作就把数据同步到主内存中。 * 一个变量在同一时刻只允许一条线程进行lock操作,但lock操作可以被同一线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。 * 如果对一个变量进行lock操作后,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作。 * 如果一个变量事先没有被lock操作锁定,那就不允许对它进行unlock操作。也不允许去unlock一个被其他线程锁定的变量。 * 对一个变量执行unLock操作之前,必须要把次变量同步到主内存中(执行store,write操作) ## Happens-Before 原则 编译器、处理器都会对代码进行重排序,如果让程序员再去了解这些底层的实现以及具体规则,那么程序员的负担就太重了,严重影响了并发编程的效率。 因此,JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证(如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见) 具体的一共有六项规则: * 程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。 * 监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。 * volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。 * 传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。 * start()规则:如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。 * join()规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。 * 程序中断规则:对线程interrupted()方法的调用先行于被中断线程的代码检测到中断时间的发生。 * 对象finalize规则:一个对象的初始化完成(构造函数执行结束)先行于发生它的finalize()方法的开始。 ## 参考资料 [Java并发编程:JAVA的内存模型](https://blog.csdn.net/fei20121106/article/details/83186171)