Java 并发面试的第一层,通常不是上来就问 AQS 和锁升级,而是先看你能不能把几个基础概念说清楚。
进程是什么,线程是什么,并发和并行有什么区别,线程怎么创建,run() 和 start() 有什么区别,线程有哪些状态,wait() 和 sleep() 又差在哪里。
这些问题看起来碎,其实都在问一件事:一个任务从代码变成 CPU 上执行的指令,中间到底经历了什么。
进程和线程怎么区分
程序只是躺在磁盘上的文件。它要运行起来,就要把指令加载到 CPU,把数据加载到内存,还要管理文件、网络、磁盘这些资源。
这个正在运行的程序实例,就是进程。
线程则更轻。一个线程可以理解成一条指令流,它把自己的指令一条一条交给 CPU 执行。一个进程里面可以有一个线程,也可以有多个线程。
#mermaid-svg-Tst8ERo5Vs6zGoln{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Tst8ERo5Vs6zGoln .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Tst8ERo5Vs6zGoln .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Tst8ERo5Vs6zGoln .error-icon{fill:#552222;}#mermaid-svg-Tst8ERo5Vs6zGoln .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Tst8ERo5Vs6zGoln .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Tst8ERo5Vs6zGoln .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Tst8ERo5Vs6zGoln .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Tst8ERo5Vs6zGoln .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Tst8ERo5Vs6zGoln .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Tst8ERo5Vs6zGoln .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Tst8ERo5Vs6zGoln .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Tst8ERo5Vs6zGoln .marker.cross{stroke:#333333;}#mermaid-svg-Tst8ERo5Vs6zGoln svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Tst8ERo5Vs6zGoln p{margin:0;}#mermaid-svg-Tst8ERo5Vs6zGoln .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Tst8ERo5Vs6zGoln .cluster-label text{fill:#333;}#mermaid-svg-Tst8ERo5Vs6zGoln .cluster-label span{color:#333;}#mermaid-svg-Tst8ERo5Vs6zGoln .cluster-label span p{background-color:transparent;}#mermaid-svg-Tst8ERo5Vs6zGoln .label text,#mermaid-svg-Tst8ERo5Vs6zGoln span{fill:#333;color:#333;}#mermaid-svg-Tst8ERo5Vs6zGoln .node rect,#mermaid-svg-Tst8ERo5Vs6zGoln .node circle,#mermaid-svg-Tst8ERo5Vs6zGoln .node ellipse,#mermaid-svg-Tst8ERo5Vs6zGoln .node polygon,#mermaid-svg-Tst8ERo5Vs6zGoln .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Tst8ERo5Vs6zGoln .rough-node .label text,#mermaid-svg-Tst8ERo5Vs6zGoln .node .label text,#mermaid-svg-Tst8ERo5Vs6zGoln .image-shape .label,#mermaid-svg-Tst8ERo5Vs6zGoln .icon-shape .label{text-anchor:middle;}#mermaid-svg-Tst8ERo5Vs6zGoln .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Tst8ERo5Vs6zGoln .rough-node .label,#mermaid-svg-Tst8ERo5Vs6zGoln .node .label,#mermaid-svg-Tst8ERo5Vs6zGoln .image-shape .label,#mermaid-svg-Tst8ERo5Vs6zGoln .icon-shape .label{text-align:center;}#mermaid-svg-Tst8ERo5Vs6zGoln .node.clickable{cursor:pointer;}#mermaid-svg-Tst8ERo5Vs6zGoln .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Tst8ERo5Vs6zGoln .arrowheadPath{fill:#333333;}#mermaid-svg-Tst8ERo5Vs6zGoln .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Tst8ERo5Vs6zGoln .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Tst8ERo5Vs6zGoln .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Tst8ERo5Vs6zGoln .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Tst8ERo5Vs6zGoln .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Tst8ERo5Vs6zGoln .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Tst8ERo5Vs6zGoln .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Tst8ERo5Vs6zGoln .cluster text{fill:#333;}#mermaid-svg-Tst8ERo5Vs6zGoln .cluster span{color:#333;}#mermaid-svg-Tst8ERo5Vs6zGoln div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Tst8ERo5Vs6zGoln .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Tst8ERo5Vs6zGoln rect.text{fill:none;stroke-width:0;}#mermaid-svg-Tst8ERo5Vs6zGoln .icon-shape,#mermaid-svg-Tst8ERo5Vs6zGoln .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Tst8ERo5Vs6zGoln .icon-shape p,#mermaid-svg-Tst8ERo5Vs6zGoln .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Tst8ERo5Vs6zGoln .icon-shape .label rect,#mermaid-svg-Tst8ERo5Vs6zGoln .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Tst8ERo5Vs6zGoln .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Tst8ERo5Vs6zGoln .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Tst8ERo5Vs6zGoln :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 程序文件
进程
线程 1
线程 2
线程 3
独立内存空间 / IO 资源
共享进程内存
面试里可以这样说:
| 对比点 | 进程 | 线程 |
|---|---|---|
| 本质 | 正在运行的程序实例 | 进程内的一条执行路径 |
| 内存 | 不同进程通常有独立内存空间 | 同一进程内线程共享内存 |
| 切换成本 | 较高 | 较低 |
| 关系 | 一个进程可以包含多个线程 | 线程依附于进程存在 |
一句话总结就是:进程负责资源边界,线程负责执行路径。
并发和并行不是一回事
并发是同一时间段内应对多件事情,并行是同一时刻真正同时做多件事情。
单核 CPU 也能并发,因为操作系统会把 CPU 时间片分给不同线程。线程切换得很快,人看起来像同时执行,但微观上还是一个线程一个线程轮流跑。
多核 CPU 才能真正并行。比如 4 核 CPU 在某个时刻可以同时执行 4 个线程。
#mermaid-svg-kyakRkMqiYAvwjvX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kyakRkMqiYAvwjvX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kyakRkMqiYAvwjvX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kyakRkMqiYAvwjvX .error-icon{fill:#552222;}#mermaid-svg-kyakRkMqiYAvwjvX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kyakRkMqiYAvwjvX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kyakRkMqiYAvwjvX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kyakRkMqiYAvwjvX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kyakRkMqiYAvwjvX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kyakRkMqiYAvwjvX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kyakRkMqiYAvwjvX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kyakRkMqiYAvwjvX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kyakRkMqiYAvwjvX .marker.cross{stroke:#333333;}#mermaid-svg-kyakRkMqiYAvwjvX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kyakRkMqiYAvwjvX p{margin:0;}#mermaid-svg-kyakRkMqiYAvwjvX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kyakRkMqiYAvwjvX .cluster-label text{fill:#333;}#mermaid-svg-kyakRkMqiYAvwjvX .cluster-label span{color:#333;}#mermaid-svg-kyakRkMqiYAvwjvX .cluster-label span p{background-color:transparent;}#mermaid-svg-kyakRkMqiYAvwjvX .label text,#mermaid-svg-kyakRkMqiYAvwjvX span{fill:#333;color:#333;}#mermaid-svg-kyakRkMqiYAvwjvX .node rect,#mermaid-svg-kyakRkMqiYAvwjvX .node circle,#mermaid-svg-kyakRkMqiYAvwjvX .node ellipse,#mermaid-svg-kyakRkMqiYAvwjvX .node polygon,#mermaid-svg-kyakRkMqiYAvwjvX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kyakRkMqiYAvwjvX .rough-node .label text,#mermaid-svg-kyakRkMqiYAvwjvX .node .label text,#mermaid-svg-kyakRkMqiYAvwjvX .image-shape .label,#mermaid-svg-kyakRkMqiYAvwjvX .icon-shape .label{text-anchor:middle;}#mermaid-svg-kyakRkMqiYAvwjvX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kyakRkMqiYAvwjvX .rough-node .label,#mermaid-svg-kyakRkMqiYAvwjvX .node .label,#mermaid-svg-kyakRkMqiYAvwjvX .image-shape .label,#mermaid-svg-kyakRkMqiYAvwjvX .icon-shape .label{text-align:center;}#mermaid-svg-kyakRkMqiYAvwjvX .node.clickable{cursor:pointer;}#mermaid-svg-kyakRkMqiYAvwjvX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kyakRkMqiYAvwjvX .arrowheadPath{fill:#333333;}#mermaid-svg-kyakRkMqiYAvwjvX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kyakRkMqiYAvwjvX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kyakRkMqiYAvwjvX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kyakRkMqiYAvwjvX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kyakRkMqiYAvwjvX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kyakRkMqiYAvwjvX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kyakRkMqiYAvwjvX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kyakRkMqiYAvwjvX .cluster text{fill:#333;}#mermaid-svg-kyakRkMqiYAvwjvX .cluster span{color:#333;}#mermaid-svg-kyakRkMqiYAvwjvX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kyakRkMqiYAvwjvX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kyakRkMqiYAvwjvX rect.text{fill:none;stroke-width:0;}#mermaid-svg-kyakRkMqiYAvwjvX .icon-shape,#mermaid-svg-kyakRkMqiYAvwjvX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kyakRkMqiYAvwjvX .icon-shape p,#mermaid-svg-kyakRkMqiYAvwjvX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kyakRkMqiYAvwjvX .icon-shape .label rect,#mermaid-svg-kyakRkMqiYAvwjvX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kyakRkMqiYAvwjvX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kyakRkMqiYAvwjvX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kyakRkMqiYAvwjvX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 单核
多核
多个任务
CPU 核心数
时间片轮转
宏观看起来同时运行
并发
多个核心同时执行
并行
可以用一句很稳的面试话术:
并发强调处理多个任务的能力,并行强调同一时刻同时执行多个任务。单核 CPU 可以并发,多核 CPU 才能在物理上并行。
线程有哪些创建方式
PPT 里列了四种:
- 继承
Thread类。 - 实现
Runnable接口。 - 实现
Callable接口,配合FutureTask拿返回值。 - 使用线程池创建线程。
继承 Thread 最直接:
java
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread...run...");
}
public static void main(String[] args) {
new MyThread().start();
}
}
实现 Runnable 更常见,因为任务和线程对象分开了:
java
Runnable task = () -> System.out.println("running...");
new Thread(task, "t1").start();
Callable 比 Runnable 多两个能力:有返回值,可以抛出异常。
java
Callable<String> task = () -> {
System.out.println(Thread.currentThread().getName());
return "ok";
};
FutureTask<String> futureTask = new FutureTask<>(task);
new Thread(futureTask, "t1").start();
String result = futureTask.get();
但真实项目里,不建议频繁 new Thread()。更常见的方式是把任务交给线程池。
java
ExecutorService threadPool = Executors.newFixedThreadPool(3);
threadPool.submit(() -> System.out.println("running..."));
threadPool.shutdown();
线程池这块后面会单独写一篇,因为它比"创建线程"复杂得多。
Runnable 和 Callable 有什么区别
这个问题很适合用表格回答:
| 对比点 | Runnable | Callable |
|---|---|---|
| 方法 | run() |
call() |
| 返回值 | 没有返回值 | 有返回值 |
| 异常 | 不能向外抛受检异常 | 可以抛异常 |
| 获取结果 | 不支持 | 配合 Future / FutureTask |
所以面试里不要只背"一个有返回值一个没有返回值"。更完整的回答是:
Runnable 更适合只执行任务、不关心结果的场景;Callable 更适合异步计算后还要拿结果或处理异常的场景。
run 和 start 有什么区别
run() 只是普通方法调用。
start() 才是真正启动一个新线程,让 JVM 创建线程并异步执行 run() 里的代码。
java
Thread t1 = new Thread("t1") {
@Override
public void run() {
System.out.println("running...");
}
};
t1.start();
如果直接调用 t1.run(),代码仍然在当前线程里同步执行,不会创建新线程。
还有一个细节,start() 只能调用一次。对同一个线程对象重复调用 start(),会抛 IllegalThreadStateException。
#mermaid-svg-ObM0FvDxoMTjGH3H{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ObM0FvDxoMTjGH3H .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ObM0FvDxoMTjGH3H .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ObM0FvDxoMTjGH3H .error-icon{fill:#552222;}#mermaid-svg-ObM0FvDxoMTjGH3H .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ObM0FvDxoMTjGH3H .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ObM0FvDxoMTjGH3H .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ObM0FvDxoMTjGH3H .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ObM0FvDxoMTjGH3H .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ObM0FvDxoMTjGH3H .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ObM0FvDxoMTjGH3H .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ObM0FvDxoMTjGH3H .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ObM0FvDxoMTjGH3H .marker.cross{stroke:#333333;}#mermaid-svg-ObM0FvDxoMTjGH3H svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ObM0FvDxoMTjGH3H p{margin:0;}#mermaid-svg-ObM0FvDxoMTjGH3H .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ObM0FvDxoMTjGH3H .cluster-label text{fill:#333;}#mermaid-svg-ObM0FvDxoMTjGH3H .cluster-label span{color:#333;}#mermaid-svg-ObM0FvDxoMTjGH3H .cluster-label span p{background-color:transparent;}#mermaid-svg-ObM0FvDxoMTjGH3H .label text,#mermaid-svg-ObM0FvDxoMTjGH3H span{fill:#333;color:#333;}#mermaid-svg-ObM0FvDxoMTjGH3H .node rect,#mermaid-svg-ObM0FvDxoMTjGH3H .node circle,#mermaid-svg-ObM0FvDxoMTjGH3H .node ellipse,#mermaid-svg-ObM0FvDxoMTjGH3H .node polygon,#mermaid-svg-ObM0FvDxoMTjGH3H .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ObM0FvDxoMTjGH3H .rough-node .label text,#mermaid-svg-ObM0FvDxoMTjGH3H .node .label text,#mermaid-svg-ObM0FvDxoMTjGH3H .image-shape .label,#mermaid-svg-ObM0FvDxoMTjGH3H .icon-shape .label{text-anchor:middle;}#mermaid-svg-ObM0FvDxoMTjGH3H .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ObM0FvDxoMTjGH3H .rough-node .label,#mermaid-svg-ObM0FvDxoMTjGH3H .node .label,#mermaid-svg-ObM0FvDxoMTjGH3H .image-shape .label,#mermaid-svg-ObM0FvDxoMTjGH3H .icon-shape .label{text-align:center;}#mermaid-svg-ObM0FvDxoMTjGH3H .node.clickable{cursor:pointer;}#mermaid-svg-ObM0FvDxoMTjGH3H .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ObM0FvDxoMTjGH3H .arrowheadPath{fill:#333333;}#mermaid-svg-ObM0FvDxoMTjGH3H .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ObM0FvDxoMTjGH3H .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ObM0FvDxoMTjGH3H .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ObM0FvDxoMTjGH3H .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ObM0FvDxoMTjGH3H .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ObM0FvDxoMTjGH3H .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ObM0FvDxoMTjGH3H .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ObM0FvDxoMTjGH3H .cluster text{fill:#333;}#mermaid-svg-ObM0FvDxoMTjGH3H .cluster span{color:#333;}#mermaid-svg-ObM0FvDxoMTjGH3H div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ObM0FvDxoMTjGH3H .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ObM0FvDxoMTjGH3H rect.text{fill:none;stroke-width:0;}#mermaid-svg-ObM0FvDxoMTjGH3H .icon-shape,#mermaid-svg-ObM0FvDxoMTjGH3H .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ObM0FvDxoMTjGH3H .icon-shape p,#mermaid-svg-ObM0FvDxoMTjGH3H .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ObM0FvDxoMTjGH3H .icon-shape .label rect,#mermaid-svg-ObM0FvDxoMTjGH3H .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ObM0FvDxoMTjGH3H .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ObM0FvDxoMTjGH3H .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ObM0FvDxoMTjGH3H :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} run()
start()
Thread 对象
调用方式
普通方法调用
当前线程执行
JVM 启动新线程
新线程执行 run()
线程有哪些状态
JDK 的 Thread.State 定义了六种状态:
| 状态 | 含义 |
|---|---|
NEW |
新建,还没有调用 start() |
RUNNABLE |
可运行,可能正在运行,也可能等待 CPU 时间片 |
BLOCKED |
等待获取 monitor 锁 |
WAITING |
无限期等待,需要其他线程唤醒 |
TIMED_WAITING |
限时等待,到时间或被唤醒后继续 |
TERMINATED |
执行结束 |
状态流转可以这样看:
#mermaid-svg-6vV84wnyf1Zvly5C{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6vV84wnyf1Zvly5C .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6vV84wnyf1Zvly5C .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6vV84wnyf1Zvly5C .error-icon{fill:#552222;}#mermaid-svg-6vV84wnyf1Zvly5C .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6vV84wnyf1Zvly5C .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6vV84wnyf1Zvly5C .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6vV84wnyf1Zvly5C .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6vV84wnyf1Zvly5C .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6vV84wnyf1Zvly5C .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6vV84wnyf1Zvly5C .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6vV84wnyf1Zvly5C .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6vV84wnyf1Zvly5C .marker.cross{stroke:#333333;}#mermaid-svg-6vV84wnyf1Zvly5C svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6vV84wnyf1Zvly5C p{margin:0;}#mermaid-svg-6vV84wnyf1Zvly5C defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-6vV84wnyf1Zvly5C g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-6vV84wnyf1Zvly5C g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-6vV84wnyf1Zvly5C g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-6vV84wnyf1Zvly5C g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-6vV84wnyf1Zvly5C g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-6vV84wnyf1Zvly5C .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-6vV84wnyf1Zvly5C .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-6vV84wnyf1Zvly5C .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-6vV84wnyf1Zvly5C .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-6vV84wnyf1Zvly5C .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-6vV84wnyf1Zvly5C .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-6vV84wnyf1Zvly5C .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-6vV84wnyf1Zvly5C .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6vV84wnyf1Zvly5C .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6vV84wnyf1Zvly5C .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6vV84wnyf1Zvly5C .edgeLabel .label text{fill:#333;}#mermaid-svg-6vV84wnyf1Zvly5C .label div .edgeLabel{color:#333;}#mermaid-svg-6vV84wnyf1Zvly5C .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-6vV84wnyf1Zvly5C .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-6vV84wnyf1Zvly5C .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-6vV84wnyf1Zvly5C .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-6vV84wnyf1Zvly5C .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-6vV84wnyf1Zvly5C .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6vV84wnyf1Zvly5C .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6vV84wnyf1Zvly5C #statediagram-barbEnd{fill:#333333;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6vV84wnyf1Zvly5C .cluster-label,#mermaid-svg-6vV84wnyf1Zvly5C .nodeLabel{color:#131300;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-6vV84wnyf1Zvly5C .note-edge{stroke-dasharray:5;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-note text{fill:black;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram-note .nodeLabel{color:black;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagram .edgeLabel{color:red;}#mermaid-svg-6vV84wnyf1Zvly5C #dependencyStart,#mermaid-svg-6vV84wnyf1Zvly5C #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-6vV84wnyf1Zvly5C .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6vV84wnyf1Zvly5C :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} new Thread()
start()
等待 synchronized 锁
获得锁
wait() / join()
notify() / notifyAll()
sleep(ms) / wait(ms) / join(ms)
到时间或被唤醒
run() 执行结束
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
有一个容易说错的点:Java 里的 RUNNABLE 包括操作系统层面的"就绪"和"运行"。所以线程进入 RUNNABLE,不代表它此刻一定正在占用 CPU。
join 怎么保证线程顺序执行
如果新建 T1、T2、T3 三个线程,要保证它们按顺序执行,可以用 join()。
join() 的含义是:当前线程等待目标线程执行结束。
java
Thread t1 = new Thread(() -> System.out.println("t1"));
Thread t2 = new Thread(() -> {
try {
t1.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("t2");
});
Thread t3 = new Thread(() -> {
try {
t2.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("t3");
});
t1.start();
t2.start();
t3.start();
线程 T3 线程 T2 线程 T1 线程 T3 线程 T2 线程 T1 #mermaid-svg-z1ORY3TCajBFzj16{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-z1ORY3TCajBFzj16 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-z1ORY3TCajBFzj16 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-z1ORY3TCajBFzj16 .error-icon{fill:#552222;}#mermaid-svg-z1ORY3TCajBFzj16 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-z1ORY3TCajBFzj16 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-z1ORY3TCajBFzj16 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-z1ORY3TCajBFzj16 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-z1ORY3TCajBFzj16 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-z1ORY3TCajBFzj16 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-z1ORY3TCajBFzj16 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-z1ORY3TCajBFzj16 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-z1ORY3TCajBFzj16 .marker.cross{stroke:#333333;}#mermaid-svg-z1ORY3TCajBFzj16 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-z1ORY3TCajBFzj16 p{margin:0;}#mermaid-svg-z1ORY3TCajBFzj16 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-z1ORY3TCajBFzj16 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-z1ORY3TCajBFzj16 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-z1ORY3TCajBFzj16 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-z1ORY3TCajBFzj16 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-z1ORY3TCajBFzj16 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-z1ORY3TCajBFzj16 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-z1ORY3TCajBFzj16 .sequenceNumber{fill:white;}#mermaid-svg-z1ORY3TCajBFzj16 #sequencenumber{fill:#333;}#mermaid-svg-z1ORY3TCajBFzj16 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-z1ORY3TCajBFzj16 .messageText{fill:#333;stroke:none;}#mermaid-svg-z1ORY3TCajBFzj16 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-z1ORY3TCajBFzj16 .labelText,#mermaid-svg-z1ORY3TCajBFzj16 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-z1ORY3TCajBFzj16 .loopText,#mermaid-svg-z1ORY3TCajBFzj16 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-z1ORY3TCajBFzj16 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-z1ORY3TCajBFzj16 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-z1ORY3TCajBFzj16 .noteText,#mermaid-svg-z1ORY3TCajBFzj16 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-z1ORY3TCajBFzj16 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-z1ORY3TCajBFzj16 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-z1ORY3TCajBFzj16 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-z1ORY3TCajBFzj16 .actorPopupMenu{position:absolute;}#mermaid-svg-z1ORY3TCajBFzj16 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-z1ORY3TCajBFzj16 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-z1ORY3TCajBFzj16 .actor-man circle,#mermaid-svg-z1ORY3TCajBFzj16 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-z1ORY3TCajBFzj16 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 执行任务join 等待 T1 结束T1 结束执行任务join 等待 T2 结束T2 结束执行任务
notify 和 notifyAll 有什么区别
notify() 和 notifyAll() 都是唤醒在同一个对象监视器上 wait() 的线程。
区别很简单:
| 方法 | 效果 |
|---|---|
notify() |
随机唤醒一个等待线程 |
notifyAll() |
唤醒所有等待线程,让它们重新竞争锁 |
注意,唤醒不等于立刻执行。被唤醒的线程要先从 WAITING 回到可竞争状态,等当前线程释放锁之后,才能重新抢锁。
wait 和 sleep 有什么区别
这也是高频题,最好按三个维度回答。
| 对比点 | wait | sleep |
|---|---|---|
| 所属类 | Object 成员方法 |
Thread 静态方法 |
| 使用前提 | 必须先获得对象锁 | 不要求持有锁 |
| 是否释放锁 | 会释放对象锁 | 不会释放已持有的锁 |
| 唤醒方式 | notify / notifyAll / 超时 / 中断 |
超时 / 中断 |
最关键的一句是:
wait 是对象监视器上的等待,会释放锁;sleep 只是让当前线程暂停一会儿,不会释放锁。
#mermaid-svg-y5nBhwDCpJEUBHi2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-y5nBhwDCpJEUBHi2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-y5nBhwDCpJEUBHi2 .error-icon{fill:#552222;}#mermaid-svg-y5nBhwDCpJEUBHi2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-y5nBhwDCpJEUBHi2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-y5nBhwDCpJEUBHi2 .marker.cross{stroke:#333333;}#mermaid-svg-y5nBhwDCpJEUBHi2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-y5nBhwDCpJEUBHi2 p{margin:0;}#mermaid-svg-y5nBhwDCpJEUBHi2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-y5nBhwDCpJEUBHi2 .cluster-label text{fill:#333;}#mermaid-svg-y5nBhwDCpJEUBHi2 .cluster-label span{color:#333;}#mermaid-svg-y5nBhwDCpJEUBHi2 .cluster-label span p{background-color:transparent;}#mermaid-svg-y5nBhwDCpJEUBHi2 .label text,#mermaid-svg-y5nBhwDCpJEUBHi2 span{fill:#333;color:#333;}#mermaid-svg-y5nBhwDCpJEUBHi2 .node rect,#mermaid-svg-y5nBhwDCpJEUBHi2 .node circle,#mermaid-svg-y5nBhwDCpJEUBHi2 .node ellipse,#mermaid-svg-y5nBhwDCpJEUBHi2 .node polygon,#mermaid-svg-y5nBhwDCpJEUBHi2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-y5nBhwDCpJEUBHi2 .rough-node .label text,#mermaid-svg-y5nBhwDCpJEUBHi2 .node .label text,#mermaid-svg-y5nBhwDCpJEUBHi2 .image-shape .label,#mermaid-svg-y5nBhwDCpJEUBHi2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-y5nBhwDCpJEUBHi2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-y5nBhwDCpJEUBHi2 .rough-node .label,#mermaid-svg-y5nBhwDCpJEUBHi2 .node .label,#mermaid-svg-y5nBhwDCpJEUBHi2 .image-shape .label,#mermaid-svg-y5nBhwDCpJEUBHi2 .icon-shape .label{text-align:center;}#mermaid-svg-y5nBhwDCpJEUBHi2 .node.clickable{cursor:pointer;}#mermaid-svg-y5nBhwDCpJEUBHi2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-y5nBhwDCpJEUBHi2 .arrowheadPath{fill:#333333;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-y5nBhwDCpJEUBHi2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y5nBhwDCpJEUBHi2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-y5nBhwDCpJEUBHi2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y5nBhwDCpJEUBHi2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-y5nBhwDCpJEUBHi2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-y5nBhwDCpJEUBHi2 .cluster text{fill:#333;}#mermaid-svg-y5nBhwDCpJEUBHi2 .cluster span{color:#333;}#mermaid-svg-y5nBhwDCpJEUBHi2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-y5nBhwDCpJEUBHi2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-y5nBhwDCpJEUBHi2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-y5nBhwDCpJEUBHi2 .icon-shape,#mermaid-svg-y5nBhwDCpJEUBHi2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y5nBhwDCpJEUBHi2 .icon-shape p,#mermaid-svg-y5nBhwDCpJEUBHi2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-y5nBhwDCpJEUBHi2 .icon-shape .label rect,#mermaid-svg-y5nBhwDCpJEUBHi2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y5nBhwDCpJEUBHi2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-y5nBhwDCpJEUBHi2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-y5nBhwDCpJEUBHi2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} wait()
sleep(ms)
线程持有锁
调用方法
释放锁
进入 WAITING / TIMED_WAITING
被 notify 或超时后重新竞争锁
不释放锁
进入 TIMED_WAITING
时间到后继续执行
如何停止一个正在运行的线程
不要用 Thread.stop()。它已经被废弃,因为它会粗暴终止线程,可能导致锁释放和数据状态都不可靠。
常见做法有两种:
- 使用退出标记,让线程自己在合适的位置结束。
- 使用
interrupt()中断线程,由线程自己决定如何响应。
阻塞中的线程,比如正在 sleep()、wait()、join(),收到中断后会抛 InterruptedException。
普通运行中的线程,interrupt() 不会强行停止它,只是把中断标记设置为 true。线程需要自己检查这个标记。
java
Thread worker = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
// do work
}
});
worker.start();
worker.interrupt();
这也是并发编程里很重要的思想:停止线程不是外部强杀,而是协作式退出。
面试怎么答
如果面试官从基础题开始问,可以把回答组织成一条线:
线程是进程内的执行路径,同一进程内的线程共享内存,所以多线程能提升吞吐,也会带来线程安全问题。
并发是多个任务交替推进,并行是多个任务同一时刻同时执行。Java 里创建线程可以继承 Thread、实现 Runnable、实现 Callable 或使用线程池,项目里更推荐线程池。
线程启动要调用 start(),直接调用 run() 只是普通方法调用。线程状态主要有 NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。其中 wait() 会释放锁,sleep() 不会释放锁。停止线程时不建议用 stop(),更推荐退出标记或 interrupt() 这种协作式方式。