深入了解jvm-2Edition-Java内存模型与线程
2021/9/18 7:07:46
本文主要是介绍深入了解jvm-2Edition-Java内存模型与线程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1、概述
现代计算机中,CPU的运算速度远远快于内存存取速度,为了更好利用CPU的硬件性能,人们想出来很多办法。
1、减小CPU和内存的速度差距——cache
通过在CPU和内存之间加入一层缓冲层,CPU的输出输入到cache中,输入从cache中获得。
然后再利用局部性原理,预先在cache中存入更多数据,来满足CPU的高速处理。
cache命中率、cache缺失、cache一致性、写缓冲、写回、写直达。
2、减少CPU等待——多任务处理
在当前任务在执行IO操作时,采用DMA方式执行IO,CPU保存当前进程的工作现场,并切换到其他进程执行。
在多处理器的CPU中,每个处理器都有自己的高速缓存,这时就引出了一个问题——缓存一致性(内存可见性)。
当多个处理器都对同一数据进行处理时,数据在处理器的缓存中可能会产生多个副本。
Java虚拟机规范中试图定义一种统一的Java内存模型来屏蔽掉硬件和操作系统内存访问的差异,从而在内存访问上实现平台无关性。
Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量储存到内存和从内存取出的底层细节。
2、Java内存模型
2.1 主内存与工作内存
Java内存模型规定所有的变量都存储在主内存中。
每个线程有自己的工作内存,其中保存了该线程使用到的变量的主内存副本拷贝(引用)。
线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。
线程间的变量值的传递均需要通过主内存来完成。
2.2 内存间交互操作
如何在主内存和工作内存之间传递数据?
Java内存模型规定了8种操作:
1、lock
作用于主内存的变量,把变量标识为一条线程独占的状态。
2、unlock
将主内存变量从锁定状态释放。释放后的变量才能被其他线程锁定。
3、read
作用于主内存变量,把变量值从主内存传输入工作内存,以便后面的load操作使用。
4、load
作用于工作内存的变量,把read操作输入的值放入工作内存的变量副本中。
5、use
作用于工作内存变量,将工作内存变量值传递给执行引擎(当虚拟机执行到需要变量值的指令时)。
6、assign
作用于工作内存变量,把从执行引擎收到的值赋给工作内存变量。
7、store
作用于工作内存变量,把变量值传送到主内存中。以便后面的write指令使用。
8、write作用于主内存变量,把store操作传过来的值放入主内存的变量中。
执行以上8种操作需要满足以下规则:
1、read和load,store和write必须配对出现。不能存在输入但不接收的情况。
2、不允许一个线程丢弃它最近的assign操作,变量在工作内存中改变后必须同步回主内存。
3、不允许一个线程无原因(没有改变)地将数据同步回主内存。
4、新的变量只能在主内存中产生,使用变量前,必须经过assign和load操作。
5、一个变量同一时刻只能有一个线程对其进行lock操作。但是,可以被一个线程多次执行lock操作(重入)。
6、如果对变量执行lock操作,那么会清空工作内存中变量的值,使用前需要重新load或赋值。
7、unlock必须在lock之后才能进行。
8、对变量执行unlock之前,必须同步回内存。
主内存--->工作内存:read--->load 按先后顺序执行,没有原子性要求。
工作内存--->主内存:store--->write 按先后顺序执行,没有原子性要求。
对于volatile类型变量的特殊规则:
1、可见性
一个线程修改了变量值,其他线程立即可以知道这个修改。
没有保证原子性。因此,read->change->write的操作(依赖当前值)是不安全的。
2、禁止指令重排序
在本地代码中插入了许多内存屏障来保证处理器不发生乱序执行。
对于long、double类型的特殊规则:
非原子协定:对于64位数据类型的读写可以采用两条32位指令来实现,且不强制两条指令的原子性。
2.3 先行发生规则
3、Java与多线程
线程是比进程更轻量级的调度执行单位,线程的引入,可以把进程的资源分配和调度执行分开。
各个线程既可以共享进程资源(内存、IO),又可以独立的被调度运行。
3.1 线程实现
1、使用内核线程实现
内核线程(Kernal-Level Thread):直接由操作系统内核支持和管理的线程。
轻量级进程(Light Weight Process):内核线程的接口,用于程序调用。
使用内核线程实现就是在程序中调用轻量级进程接口,将线程的实现交给操作系统。
LWP:KLT=1:1。
线程切换代价太高,支持的线程数量有限。
2、使用用户线程实现
自己在程序中实现线程的建立、同步、销毁和调度。
切换效率高,实现复杂。
3、使用用户线程+内核线程 的混合模式
创建、切换销毁自己实现,调度和处理器映射则依赖操作系统。
UT(user thread):LWP:KLT=m:n:n。
折中。
3.2 Java线程实现
Linux和windows都是1:1的实现。
4、Java线程调度
抢占式和非抢占式。
Java使用抢占式。
线程优先级,Java有10个等级,但是最终都要映射到操作系统的优先级上。
Windows有7个等级。
Java线程状态:
1、New
创建后尚未启动。
2、Runable
包括操作系统中的Running和Ready状态。
3、Waiting
无限期地等待,直到被显示地唤醒。
没有设Timeout参数的Object.wait()方法和Thread.join()方法;
LockSupport.park() 方法。
4、Timed Waiting
一段时间后自动苏醒。
Thread.sleep()方法;
设置了Timeout参数的Object.wait和Thread.join方法;
LockSupport.parkNanos()方法;
LockSupport.parkUtil()方法。
5、Blocked
6、Terminated
这篇关于深入了解jvm-2Edition-Java内存模型与线程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-11cursor试用出现:Too many free trial accounts used on this machine 的解决方法
- 2025-01-11百万架构师第十四课:源码分析:Spring 源码分析:深入分析IOC那些鲜为人知的细节|JavaGuide
- 2025-01-11不得不了解的高效AI办公工具API
- 2025-01-102025 蛇年,J 人直播带货内容审核团队必备的办公软件有哪 6 款?
- 2025-01-10高效运营背后的支柱:文档管理优化指南
- 2025-01-10年末压力山大?试试优化你的文档管理
- 2025-01-10跨部门协作中的进度追踪重要性解析
- 2025-01-10总结 JavaScript 中的变体函数调用方式
- 2025-01-10HR团队如何通过数据驱动提升管理效率?6个策略
- 2025-01-10WBS实战指南:如何一步步构建高效项目管理框架?