Java虚拟机--内存模型与线程

时间:2022-12-27 20:21:45

0、内存模型

内存模型,可以理解为特定操作协议下,对指定的内存或高速缓存进行读写访问的过程抽象。C/C++直接使用物理硬件和操作系统的内存模型,会有不同平台的差异性。

Java虚拟机--内存模型与线程

1、Java内存模型

参考书籍:深入理解Java内存模型
Java虚拟机规范试图定义一种Java内存模型,来屏蔽掉不同平台的差异。

1)主存与工作内存

主内存与工作内存与Java内存区域中的Java堆、栈、方法并不是一个层次的内存划分(抽象方式不同),可以勉强把主内存看做Java堆中对象的实例数据部分(对象中其实还有GC标志、年龄、同步锁等),把工作内存看做虚拟机栈中的部分区域。
Java虚拟机--内存模型与线程

2)内存间交互操作

8种原子性操作
Java虚拟机--内存模型与线程
Java虚拟机--内存模型与线程

执行以上8种操作时,必须满足以下规则:
Java虚拟机--内存模型与线程
Java虚拟机--内存模型与线程

3)volatile型变量

保证可见性禁止重排序没有原子性

每次修改完某变量的值就立马同步回内存,每次要使用该变量时都要从主内存刷新。
volatile的使用场景

4)long和double型变量的特殊规则

JMM允许虚拟机将没有被volatile修饰的64位数据的读写操作分为两次32位的操作来进行,即不保证64位数据的原子性。但是,目前JVM都会把long和double数据的操作实现为原子性的,来避免线程同步问题

5)原子性、可见性、有序性

  • 原子性:JMM保证的8种原子性操作,syncronized保证更大的原子性操作
  • 可见性:一个线程修改了一个变量的值,对于其他线程是立即可见的,因为该线程会立即把修改后的值同步回内存(volatile)。syncronized和final都具备可见性。同步块在对一个变量unlock之前会先把该变量同步回主内存。
  • 有序性

6)先行发生原则

判断数据是否存在竞争、线程是否安全。
Java虚拟机--内存模型与线程

2、Java与线程

1)线程的实现

a、使用内核级线程实现

内核线程(Kernel-Level Thread, KLT),由内核来完成线程切换。一般不会直接使用内核线程,而失去使用内核线程的高级接口—轻量级进程(Light Weight Process, LWP),即通常意义上所讲的线程。每个轻量级进程都由一个内核级线程支持,这种轻量级进程和内核线程之间1:1的关系称为一对一线程模型。
Java虚拟机--内存模型与线程
局限性:轻量级进程有内核线程支持实现,各种操作要进行系统调度,在用户态与系统态之间来回切换代价极高。而且,内核级线程在内核中是有限的。

b、使用用户线程实现

在用户态实现,快速且低消耗。进程与用户线程为1对N的关系。
Java虚拟机--内存模型与线程

局限性: 没有内核支援,线程的 创建、切换、调度有用户自己实现,“阻塞”、“如何将线程映射到多处理器系统的其他处理器上”等问题较难解决,用户线程实现的程序较为复杂。

c、用户线程加轻量级进程混合实现

在一对一的轻量级进程上,创建多个线程,用户线程与轻量级进程N:M关系
Java虚拟机--内存模型与线程

d、Java线程的实现

Windows和Linux版采用一对一模型,Solaris平台既可以采用一对一模型,也可采用多对多模型。

2)Java线程调度

线程的调度主要有两种方式:

  • 协同式调度:执行时间由线程自己来控制。实现简单,但是当此线程发生死循环时,就会造成系统不稳定,因为他永不让出处理器。
  • 抢占式调度:由系统分配时间。线程有一定自主权:a、让出时间,Thread.yield;b、“建议”优先执行,设定优先级。

Java采用抢占式调度。

3)线程状态转换

五种状态:
1. 新建(New)
2. 运行(Runnable)
3. 无限期等待(Waiting):不会被分配CPU执行时间,等待显式唤醒,否则无限期等待。有以下方法:
Java虚拟机--内存模型与线程
4. 限期等待(Timed Waiting):不会被分配CPU执行时间,一定时间内会由系统自动唤醒,有以下方法:
Java虚拟机--内存模型与线程
5. 阻塞(Blocked):在等待获得一个排它锁。
6. 结束(Terminated)

线程状态转换图
Java虚拟机--内存模型与线程