Java内存模型最全详解(定义作用及5大模型图解)

Java内存模型最全详解(定义作用及5大模型图解)-mikechen

Java内存模型经常在Java面试被问到,比如:Java内存模型作用与实现等,下面重点详解Java内存模型@mikechen

Java内存模型定义

Java内存模型,全称Java Memory Model,简称JMM,是Java程序运行时内存的抽象概念,描述了Java程序如何在内存中存储和访问数据。

 

Java内存模型作用

Java内存模型定义了一些规则和原则,比如:规定了线程如何与内存进行交互,包括线程之间的同步和数据共享,作用就是:确保程序的正确性和一致性。

 

Java内存模型实现

Java内存模型中主要包括以下内容:

1.主内存(Main Memory)

Java内存模型中的主内存(Main Memory)是所有线程共享的内存区域,用于存储Java程序中的变量和对象实例等数据。

如下图黄色部分所示:

Java内存模型最全详解(定义作用及5大模型图解)-mikechen

所有的变量都存储在主内存中,包括静态变量、实例变量和数组元素等。

主内存可以被所有线程访问,但线程不能直接访问主内存中的变量。

只能通过将主内存中的变量读取到自己的工作内存中,或将自己工作内存中的变量写回主内存中,来实现对主内存的访问。

在Java内存模型中,主内存具有以下特点:

  1. 所有线程都可以访问主内存中的数据。
  2. 主内存中的数据是线程间共享的,因此在多线程环境下,需要使用同步机制来保证数据的一致性。
  3. 主内存中的数据可以被多个线程同时访问,但是在同一时刻只能被一个线程修改。
  4. 主内存中的数据对于所有线程都是可见的,即当一个线程修改了主内存中的数据后,其他线程可以立即看到这些修改。

因为主内存中的数据可以被多个线程同时访问,因此需要使用同步机制来保证多个线程对同一数据的访问顺序和正确性。

Java中提供了SynchronizedVolatileReentrantLock等同步机制来保证多线程程序的正确性和一致性。

 

2.工作内存(Working Memory)

Java内存模型中每个线程都有自己的工作内存(Working Memory),也称为本地内存(Local Memory),用于存储线程执行时需要使用的变量和对象实例等数据。

每个线程的工作内存都是独立的,只能通过读取和写入自己的工作内存来间接访问主内存。

如下图所示:

Java内存模型最全详解(定义作用及5大模型图解)-mikechen

在Java内存模型中,工作内存具有以下特点:

  1. 每个线程都有自己的工作内存,工作内存不共享。
  2. 线程不能直接访问主内存中的变量和对象实例,只能通过工作内存来访问。
  3. 每个线程对变量的操作都是在自己的工作内存中进行的,不会影响其他线程的操作。
  4. 线程之间通过将自己的工作内存中的数据写回主内存,或将主内存中的数据读取到自己的工作内存来实现数据的共享。

 

3.内存间交互操作

Java内存模型中,内存交互操作是指线程间进行数据通信的操作,包括读操作、写操作和锁定操作等。

如下图绿色部分,所示:

Java内存模型最全详解(定义作用及5大模型图解)-mikechen

内存交互操作可以保证线程间对变量的操作顺序和正确性,保证多线程程序的正确性和一致性。

Java内存模型定义了以下内存交互操作,主要分为以下8种:

1.lock(锁定)

lock作用于主内存的变量,它把一个变量标识为一条线程独占的状态。

2.unlock(解锁)

unlock作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。

3.read(读取)

read作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。

4.load(载入)

load作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。

5.use(使用)

use作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。

6.assign(赋值)

assign作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。

7.store(存储)

store作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。

8.write(写入)

write作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。

 

4.Happens-Before规则

Java内存模型中的Happens-Before规则是指在多线程环境下,为了保证程序正确性,程序中的操作需要满足一定的顺序关系,即Happens-Before关系。

Happens-Before规则包括以下几种:

  1. 程序顺序规则(Program Order Rule):对于单个线程中的操作,Happens-Before规则保证该线程中的每个操作按照程序顺序执行,即程序中的操作顺序一定是线程中的执行顺序。
  2. 管程锁定规则(Monitor Lock Rule):对于一个锁的解锁操作,Happens-Before规则保证该锁的下一个锁定操作一定能够看到该锁的解锁操作。
  3. volatile变量规则(Volatile Variable Rule):对于一个volatile变量的写操作,Happens-Before规则保证其他线程的读操作一定能够看到该变量的更新值。
  4. 传递性规则(Transitivity):如果操作A Happens-Before操作B,操作B Happens-Before操作C,那么操作A Happens-Before操作C。
  5. 线程启动规则(Thread Start Rule):对于一个线程的启动操作,Happens-Before规则保证该线程中的操作一定能够看到主线程中在该线程启动之前的操作。
  6. 线程终止规则(Thread Termination Rule):对于一个线程的终止操作,Happens-Before规则保证该线程中的操作一定能够看到该线程在终止之前的操作。
  7. 线程中断规则(Thread Interruption Rule):对于一个线程的中断操作,Happens-Before规则保证该线程中的操作一定能够看到该线程在中断之前的操作。

Happens-Before规则是Java内存模型中非常重要的概念,它能够保证多线程程序的正确性和一致性。

 

5.原子性、可见性和有序性

Java内存模型中的原子性、可见性和有序性是指多线程环境下,程序中的操作需要满足一定的特性,以保证程序的正确性和一致性。

1.原子性(Atomicity)

原子性指的是一个操作或者多个操作要么全部执行成功,要么全部执行失败,不会出现中间状态。在Java中,原子性操作可以通过synchronized关键字、Lock对象、Atomic包中的原子类等方式来实现。

2.可见性(Visibility)

可见性指的是一个线程对共享变量的修改,能够被其他线程立即看到,不会出现数据不一致的情况。在Java中,可见性可以通过volatile关键字、synchronized关键字等方式来实现。

3.有序性(Ordering)

有序性指的是程序中的操作在执行时按照一定的顺序执行,不会出现随机性和乱序执行的情况。在Java中,有序性可以通过synchronized关键字、volatile关键字等方式来实现。

在编写多线程程序时,需要同时考虑这三个特性,以保证程序的正确性和一致性。

以上就是Java内存模型的详解,更多Java多线程内存,请查看:Java多线程编程详解(看这篇就足够了)

作者简介

陈睿|mikechen,10年+大厂架构经验,BAT资深面试官,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

👇阅读更多mikechen架构文章👇

阿里架构 |双11秒杀 |分布式架构 |负载均衡 |单点登录 |微服务 |云原生 |高并发 |架构师

以上

关注作者「mikechen」公众号,获取更多技术干货!

后台回复架构,即可获取《阿里架构师进阶专题全部合集》,后台回复面试即可获取《史上最全阿里Java面试题总结

评论交流
    说说你的看法