03. Java 线程内存模型

1. 前言

本节内容是从操作系统的层面谈并发,本节课程我们需要掌握如下内容:

  • 了解 Java 的内存模型定义,是 Java 并发编程基本原理的基础知识;
  • 从概念上了解线程的私有内存空间和主内存,能够从全局上了解线程是如何进行内存数据的存取操作的;
  • 了解线程拥有私有空间的意义,私有空间能够为线程提供独有的数据,其他线程不可干扰;
  • 在多线程环境下,主内存操作共享变量需要注意的事项需谨记,数据安全问题很重要;
  • Java 线程也是拥有生命周期的,了解它的生命周期,从宏观上了解线程。

2. 什么是 Java 的内存模型

定义: Java 内存模型(即 Java Memory Model,简称 JMM)本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。

3. Java 线程的私有内存和主内存

首先看下图,图中展示了Java 的内存模型。

工作内存(私有):由于JVM 运行程序的实体是线程,而每个线程创建时 JVM 都会为其创建一个工作内存(栈空间),用于存储线程私有的数据。线程私有的数据只能供自己使用,其他线程不能够访问到当前线程私有的内存空间,保证了不同的线程在处理自己的数据时,不受其他线程的影响。

主内存(共享):Java 内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问。从上图中可以看到,Java 的并发内存模型与操作系统的 CPU 运行方式极其相似,这就是 Java 的并发编程模型。通过创建多条线程,并发的进行操作,充分利用系统资源,达到高效的并发运算。

4. 线程拥有私有空间的意义

我们知道,线程的私有空间中存储的数据,仅供当前线程自己使用,其他线程不能够对数据进行访问。线程的私有空间会存放很多程序运行时所必须的数据,如:

程序计数器:记录当前方法执行到了哪里,以便 CPU 切换回来之后能够继续执行上次执行到的位置,而不会进行重复执行或者遗漏。

局部变量:局部变量是方法中的变量,只供当前方法使用。

方法参数:Java 方法会定义自己的入参,入参的真实值也会记录到内存空间供当前线程使用。

由于线程的内存空间会存放很多数据,这里只提以上三中数据以供同学理解线程私有空间的意义。

为了加深理解,我们一起看一个简单的代码示例并进行分析:

复制代码
public class DemoTest{
    public static void main(String[] args) {
        sum(10); // 解析点 3
    }
    public static void  sum(int num) {
        int i = 5; // 解析点 1
        set(); //解析点 2
        System.out.println("num+i = "+ (num + i));
    }
    public static void  set() {
        int  i = 100;
    }
}

在给出结果之前,我们来分析下:

解析点 1 :设置 i 的值为 5;

解析点 2: 调用 set() 方法,逻辑如下。

复制代码
public static void  set() {
        int  i = 100;
    }

那最终的结果是多少呢?

解析点 3:我们传入的 sum 的参数值是 10,如果想确定结果,只要确定另外一个加数 i 的值就行了。我们通过分析,在方法 sum(int num) 中的 int i = 5 与方法 set() 中的 int i = 100 是两个不同的方法的局部变量,属于线程私有的。互相不会影响,所以set() 方法中的 int i = 100 不会影响最终的结果:

复制代码
num+i = 15

5. 主内存操作共享变量需要注意的事项

  • 确定是否是多线程环境:多线程环境下操作共享变量需要考虑线程的安全性;
  • 确定是否有增删改操作:多线程环境下,如果对共享数据有增加,删除或者修改的操作,需要谨慎。为了保证线程的同步性,必须对该共享数据进行加锁操作,保证多线程环境下,所有的线程能够获取到正确的数据。如生产者与消费者模型,售票模型。这些会在后续章节进行代码实战演练;
  • 多线程下的读操作:如果是只读操作,对共享数据不需要进行锁操作,因为数据本身未发生增删改操作,不会影响获取数据的准确性。

6. Java 线程的生命周期

每个事物都有其生命周期,也就是事物从出生开始到最终消亡这中间的整个过程。在其整个生命周期的历程中,会有不同阶段,每个阶段对应着一种状态,比如:人的一生会经历从婴幼儿、青少年、青壮年、中老年到最终死亡,离开这人世间,这是人一生的状态。

同样的,线程作为一种事物,也有生命周期,在其生命周期中也存在着不同的状态,不同的状态之间还会有互相转换。

Java 线程的声明周期会经历 6 中不同的状态变化,后续章节会有详细描述。从线程的创建到线程执行任务的完成,即 Java 线程的生命周期。

7. 小结

Java 并发理论基础是基于Java 的内存模型的,了解 Java 内存模型,能够更有助于后续对并发知识的理解和运用了。Java 的内存模型是并发原理的基础,在了解内存模型的基础上去理解共享内存和私有内存,了解不同内存状态以及 Java 线程的生命周期至关重要。

相关推荐
侠客行03176 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪6 小时前
深入浅出LangChain4J
java·langchain·llm
灰子学技术7 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
老毛肚7 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎8 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
二十雨辰8 小时前
[python]-AI大模型
开发语言·人工智能·python
Yvonne爱编码8 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚8 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言
你这个代码我看不懂8 小时前
@ConditionalOnProperty不直接使用松绑定规则
java·开发语言
pas1368 小时前
41-parse的实现原理&有限状态机
开发语言·前端·javascript