JVM 允许一个应用并发执行多个线程。Hotspot JVM 中的 Java 线程与原生操作系统线程有直接的映射关系。 当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统原生线程。Java 线程结束,原生线程随之被回收。操作系统负责调度所有线程,并把它们分配到任何可用的 CPU 上。当原生线程初始化完毕,就会调用 Java 线程的 run() 方法。当线程结束时。 Hotspot JVM 后台运行的系统线程主要有下面几个:

  • 虚拟机线程,这个线程等待 JVM 到达安全点操作出现。这些操作必须要在独立的线程里执行,因为当
    堆修改无法进行时,线程都需要 JVM 位于安全点。这些操作的类型有: stop-the-world 垃圾回收、线程栈 dump、线程暂停、线程偏向锁(biased locking)解除。
  • 周期任务线程, 这线程负责定时器事件(也就是中断),用来调度周期性操作的执行
  • GC 线程, 这些线程支持 JVM 中不同的垃圾回收活动。
  • 编译器线程,这些线程在运行时将字节码动态编译成本地平台相关的机器码。
  • 信号分发线程,这个线程接收发送到 JVM 的信号并调用适当的 JVM 方法处理。

内存模型

Java内存模型规定了所有的变量(不包括局部变量与方法参数)都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。
image.png
Java工作内存一般可以抽象成以下8种操作与主内存交互:

  • lock, 作用于主内存变量,把一个变量标识为一条线程独占的状态。
  • unlock,作用于主内存的变量,把一个处于锁定状态的变量释放出来,以便其他线程锁定
  • save,作用于主内存变量,把一个变量值从主内存传输到线程的工作内存
  • load,作用于工作内存的变量,把read操作从主内存得到的变量值放入工作内存的变量副本中。
  • use,作用于工作内存中的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作
  • assign,作用于工作内存中的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作
  • store,作用于工作内存的变量,它把工作内存中一个变量的值传送给主内存,以便随后的write操作使用
  • write,作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。

    硬件并发模型

  • 缓存,为了提升CPU与内存的交互效率,在CPU与内存之间增加了高速缓存,并通过缓存一致性协议来确保主存中的数据正确性

  • 指令重排优化,CPU为了加快代码执行效率,在不影响最终结果的情况下,对代码的执行指令进行重新排序。所以,如果存在一个计算任务依赖另一个计算任务的中间结果,有可能会出错。

    原子性

    此原子是并非数据库ACID操作中的原子性,而是指该操作不会被线程机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何上下文切换。将整个操作视作一个整体是原子性的核心特征。由java内存模型来直接保证的原子性变量包括read、load、assign、use、store、write,我们大致可以认为基本数据类型的访问都是具备原子性的。

    可见性

    当一个线程修改了共享变量的值,其他线程能够立即得知这个操作,那么这个操作对其他线程是由可见性的。

    有序性

    如果在本线程内观察,所有的操作都是有序的;如果在一个线程中观察另一个线程,所有的操作都是无序的。前半句是指“线程内表现为串行语义,JVM必须更具as-if-serial语义来进行设计”,后半句是指”指令重排”现象和”工作内存主从同步延迟”现象。

    as-if-serial语义

    不管怎么重排序,单线程程序的执行结果不能被改变。编译器、内存系统和处理器都必须遵守as-if-serial语义。所以编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。但是,如果操作之间不存在数据依赖关系,这些操作就可能被编译器和处理器重排序。

    happens-before规则

    如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关系,这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。

  • 程序顺序规则: 对于单个线程中的每个操作,前继操作happens-before于该线程中的任意后续操作

  • 监视器锁规则: 对一个锁的解锁,happens-before于随后对这个锁的加锁
  • volatile变量规则: 对一个volatile域的写,happens-before于任意后续对这个volatile域的读
  • 传递性: 如果A happens-before B,且B happens-before C,那么A happens-before C。

参考:
Java线程的实现:https://my.oschina.net/goldenshaw/blog/705397