一、进程(Process)

1.1 进程概念

进程:操作系统(OS)中正在运行的应用程序

现代操作系统支持多进程同时运行,也就是我们常说的多进程机制。 例如:电脑同时运行微信、浏览器、IDEA、音乐软件,每一个软件都是一个独立进程。

1.2 多进程并发执行原理

  • 宏观上:并行执行 用户看起来所有程序好像是同时运行
  • 微观上:串行执行 CPU 同一时间只能执行一个进程。 操作系统通过分配 CPU 时间片,快速切换不同进程执行。 谁抢到 CPU 时间片,谁就拥有执行权。

核心原理:快速切换、轮流执行,实现宏观并发效果。


二、线程(Thread)

2.1 线程概念

线程:进程内部的独立执行任务单元。 一个进程可以包含多个线程,多个线程可以同时执行不同任务。

线程也被称为:轻量级进程

  • 进程开销大、独立资源多
  • 线程依附进程、共享资源、切换速度快

2.2 单线程程序

Java 默认程序是单线程程序

  • 程序从 main() 方法开始
  • 程序随着 main() 方法结束而终止
  • 这条默认线程称为:主线程

2.3 线程三大组成部分

1)CPU 资源

线程需要抢占 CPU 时间片,抢到时间片才能执行代码。

2)内存数据(核心考点)

  • 栈空间:线程独立 每一个线程拥有独立的栈内存,线程之间栈数据互不干扰。
  • 堆空间:线程共享 一个进程中的所有线程共享同一个堆内存 所以多线程可以共享对象、数组、集合等堆中数据(也是多线程安全问题的根源)

3)程序代码

通过 Java 代码定义线程任务,由 CPU 调度执行。


三、多线程代码实现方式(第一种:继承 Thread 类)

3.1 实现步骤

  1. 自定义类继承 java.lang.Thread 线程父类
  2. 重写父类 run() 方法

    线程的所有任务逻辑必须写在 run 方法中

  3. 创建自定义线程对象
  4. 调用 start() 方法开启线程

3.2 核心重点

  • run():封装线程任务,手动调用只是普通方法执行,不会开启新线程
  • start():向 JVM 注册线程,开启新线程,由 JVM 自动调用 run() 执行任务

3.3 执行原理

t.start() → JVM 启动新线程 → 自动执行 run() 方法内容


四、线程状态(等待状态详解)

4.1 线程休眠 sleep

static void sleep(long ms)
  • 作用:让当前线程进入限时等待(休眠)状态
  • 参数单位:毫秒
  • 执行效果:
    1. 线程主动释放 CPU 资源
    2. 休眠时间结束后,线程重新进入就绪状态,抢占 CPU 继续执行

4.2 线程加入 join

  • join()无限等待
  • 当前线程等待调用 join 的线程执行完毕后,再继续执行
  • 用于控制线程执行顺序

区别总结: sleep:限时等待、自动唤醒 join:无限等待、对方线程结束才唤醒


五、线程池(重点、面试必考)

5.1 线程池概念

线程池:线程容器 提前创建若干线程对象存入池中,任务提交后直接分配空闲线程执行,线程执行完毕不会销毁,可重复复用

5.2 线程池核心好处

  1. 避免频繁创建、销毁线程,节省系统资源
  2. 大幅提高执行效率
  3. 统一管理线程数量,防止并发过多导致系统崩溃

5.3 线程池核心体系(位于 java.util.concurrent 并发包)

1)Executor

线程池顶级根接口,定义线程池最基本机制

2)ExecutorService

Executor 的子接口,线程池核心功能接口 提供线程任务提交、线程池关闭等核心方法

核心方法
  • submit(Runnable task) 提交普通线程任务,无返回值
  • submit(Callable<T> task) 提交带返回值的线程任务
  • shutdown()关闭线程池,销毁所有线程对象,不再接收新任务

3)Executors

线程池工具类,提供大量静态方法,快速获取线程池对象

常用线程池
  1. static ExecutorService newFixedThreadPool(int n)固定线程池 创建指定数量的线程,线程数量固定,可复用
  2. static ExecutorService newCachedThreadPool()动态缓存线程池 任务多自动新建线程、任务少自动回收空闲线程,线程数量动态变化

六、多线程第二种实现方式:Callable 接口(带返回值)

6.1 Callable 介绍

  • 位于 java.util.concurrent 并发包
  • 作用:和 Runnable 类似,封装线程任务
  • 区别于 Runnable:支持返回值、支持抛出异常
  • 属于泛型接口,泛型约束返回值类型

6.2 核心方法

V call() throws Exception
  • 线程任务方法
  • 带有返回值
  • 可以抛出异常

6.3 Future 接收线程返回值

  • Future<T>:用于接收线程执行完毕后的返回结果
  • 线程池提交任务返回 Future 对象
  • 通过 future.get() 获取线程最终执行结果

6.4 执行流程

  1. 自定义类实现 Callable 接口
  2. 重写 call () 方法,定义任务、返回结果
  3. 线程池调用 submit () 提交任务
  4. 返回 Future 对象
  5. 调用 get() 获取线程返回值

七、本章核心考点总结(背诵版)

  1. 进程是程序,线程是进程中的执行单元,线程轻量级、开销更小
  2. 进程独占资源,线程共享堆、独立栈
  3. 宏观并行、微观串行是 CPU 时间片轮换机制
  4. Thread 类实现线程必须重写 run (),start () 开启新线程
  5. sleep 限时等待、join 无限等待
  6. 线程池核心:线程复用、减少开销、提高效率
  7. Executors 工具类创建线程池、ExecutorService 操作线程池
  8. Runnable 无返回值,Callable 带返回值、可抛异常
  9. Future 用于接收 Callable 线程返回结果
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐