一、前言
 
在计算机操作系统中,多线程是提升程序运行效率、实现并发处理的核心手段。日常开发中的接口异步处理、定时任务、批量文件处理、高并发请求处理,全部依赖多线程技术。
 
Java作为一门原生支持多线程的语言,从JDK1.0就内置了线程API,是后端开发基础必学、面试必考、项目必用的核心知识点。
 
很多初学者只会写  new Thread()  代码,但不懂线程底层逻辑、分不清线程和进程、不理解并发风险。本文从零拆解Java多线程核心基础,带你吃透进程线程区别、四种创建方式、完整生命周期、线程核心API,为后续线程池、锁机制、高并发编程打下坚实基础。
 
二、进程与线程(核心基础认知)
 
想要学好多线程,首先必须分清进程(Process) 和线程(Thread),这是并发编程的底层基石。
 
2.1 进程
 
进程是操作系统资源分配的最小单位,是独立运行的程序。
 
- 每一个进程都有独立的内存空间、CPU资源
- 进程之间相互独立、互不干扰
- 例如:电脑运行的QQ、浏览器、IDEA,每一个软件都是一个独立进程
 
2.2 线程
 
线程是CPU调度的最小单位,依附于进程存在,一个进程包含多个线程,共享进程资源。
 
- 线程共享进程的堆内存、方法区资源
- 线程拥有独立的栈内存(栈帧)
- 线程之间切换开销极小,并发效率高
 
2.3 核心区别总结
 
1. 资源归属:进程独立资源;线程共享进程资源
2. 开销成本:进程创建、销毁开销极大;线程轻量、开销极低
3. 独立性:进程崩溃互不影响;一个线程异常,可能导致整个进程崩溃
4. 包含关系:一个进程至少包含1个主线程
 
2.4 为什么要用多线程?
 
- 提升资源利用率:充分利用CPU多核性能,避免CPU空闲等待
- 提高程序响应速度:异步处理耗时任务,避免主线程阻塞
- 并发处理能力:同时处理多个请求、多个任务,适配高并发场景
 
三、Java四种线程创建方式(最全详解)
 
Java官方提供四种线程创建方式,从基础到进阶,适配不同业务场景,也是面试高频考点。
 
3.1 方式一:继承Thread类
 
自定义类继承  Thread  类,重写  run()  方法,调用  start()  启动线程。
 
代码实现
 
 
 
核心注意点
 
-  run() :只是普通方法,直接调用不会开启新线程
-  start() :真正向JVM申请创建新线程,进入就绪状态
- Java单继承限制:继承Thread后无法继承其他类,开发中较少使用
 
3.2 方式二:实现Runnable接口
 
实现  Runnable  接口,重写  run()  方法,传入Thread对象启动线程,解决单继承限制,是最常用的基础方式。
 
代码实现
 
 
 
优势
 
- 避免单继承局限性
- 任务和线程分离,解耦性更强
- 适合资源共享场景(多个线程执行同一个任务)
 
3.3 方式三:实现Callable接口(带返回值线程)
 
前两种方式的  run()  方法无返回值、无法抛出异常。
 Callable  是JDK5新增接口,支持线程执行完毕返回结果、抛出异常,配合  FutureTask  使用。
 
代码实现
 
 
 
适用场景
 
需要异步获取任务执行结果的场景,如批量计算、接口异步查询数据。
 
3.4 方式四:线程池创建(企业级开发首选)
 
前三种方式都是手动创建线程,频繁创建、销毁线程会造成极大性能损耗。
JDK5提供线程池,统一管理线程,复用线程资源,是生产环境唯一推荐使用的方式。
 
简单示例:
 
 
 
四、线程完整生命周期(面试重中之重)
 
Java线程从创建到销毁,一共 6种状态,由  Thread.State  枚举定义。
 
4.1 六大状态详解
 
1. NEW(新建状态)
线程对象创建完毕,未调用  start()  方法,仅存在Java对象,无操作系统线程。
2. RUNNABLE(就绪/运行状态)
调用  start()  后进入就绪状态,等待CPU调度;获取CPU时间片后进入运行状态,Java中将两个状态合并为RUNNABLE。
3. BLOCKED(阻塞状态)
线程等待获取锁资源,其他线程释放锁后,重新进入就绪状态。
4. WAITING(无限等待)
线程主动休眠,无超时时间,需要其他线程主动唤醒( wait() 、 join() )。
5. TIMED_WAITING(限时等待)
限时阻塞,时间结束自动唤醒,如  sleep(毫秒) 、 wait(时间) 。
6. TERMINATED(终止状态)
线程任务执行完毕、异常终止,线程彻底销毁。
 
4.2 核心状态流转
 
新建 → 启动(start)→ 就绪/运行 → 阻塞/等待 → 运行 → 终止
 
五、线程核心常用API
 
5.1 Thread.sleep()
 
- 让当前线程限时休眠,进入TIMED_WAITING状态
- 不释放锁!休眠期间依旧持有锁资源
 
 
 
5.2 Thread.currentThread()
 
获取当前正在执行的线程对象,常用于打印线程名称:
 
 
 
5.3 wait() / notify() / notifyAll()
 
-  wait() :让当前线程无限等待,释放锁资源
-  notify() :随机唤醒一个等待线程
-  notifyAll() :唤醒所有等待线程
 
注意:只能在同步代码块/同步方法中使用!
 
5.4 join()
 
线程插队,让当前线程等待join的线程执行完毕后,再继续执行,常用于线程顺序控制。
 
5.5 setDaemon() 守护线程
 
Java线程分为:用户线程(默认)、守护线程
 
- 用户线程:主线程结束,用户线程继续执行
- 守护线程:依附主线程,主线程退出,守护线程直接终止
- 典型场景:GC垃圾回收线程
 
六、多线程并发安全问题(入门铺垫)
 
多线程最大的问题:线程不安全
多个线程同时操作共享资源,会出现数据覆盖、数据错乱问题。
 
简单演示线程不安全:
 
 
 
原因:累加操作不具备原子性,多线程读写覆盖。
解决方案:同步锁  synchronized 、Lock锁、原子类(后续进阶博客详解)。
 
七、全文总结
 
1. 进程是资源单位,线程是调度单位,线程共享进程资源、开销更低;
2. 线程四种创建方式:Thread类、Runnable接口、Callable带返回值、线程池(生产首选);
3. 线程六大生命周期:新建、就绪、运行、阻塞、等待、终止;
4. sleep不释放锁、wait释放锁,是面试高频区别点;
5. 多线程核心痛点:共享资源并发不安全,需要锁机制保证数据一致性。
 
本篇为多线程基础全集,下一篇将进阶讲解:synchronized底层原理、volatile关键字、线程池七大参数、四种拒绝策略,带你彻底吃透Java高并发核心。

Logo

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

更多推荐