首页 简历|笔试面试

面渣逆袭并发编程篇(暗黑版)V2.1

  • 25年9月4日 发布
  • 26.99MB 共228页
面渣逆袭并发编程篇(暗黑版)V2.1面渣逆袭并发编程篇(暗黑版)V2.1面渣逆袭并发编程篇(暗黑版)V2.1面渣逆袭并发编程篇(暗黑版)V2.1面渣逆袭并发编程篇(暗黑版)V2.1

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

No. 1 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

前⾔

4 万字 145 张⼿绘图,详解 71 道 Java 多线程⾯试⾼频题(让天下没有难背的⼋股),⾯渣

背会这些并发编程⼋股⽂,这次吊打⾯试官,我觉得稳了(⼿动 dog)。

第⼀版作者是⼆哥编程星球的嘉宾三分恶,第⼆版由⼆哥结合球友们的⾯经+技术派

+PmHub+mydb 的项⽬进⾏全新升级。更适合拿来背诵突击⾯试+底层原理理解。

亮⽩版本更适合拿出来打印,这也是很多学⽣党喜欢的⽅式,打印出来背诵的效率会更⾼。

2025 年 01 ⽉ 22 ⽇开始着⼿第⼆版更新。

对于⾼频题,会标注在《Java ⾯试指南(付费)》中出现的位置,哪家公司,原题是什

么,并且会加 ,⽬录⼀⽬了然;如果你想节省时间的话,可以优先背诵这些题⽬,尽

快做到知彼知⼰,百战不殆。

No. 2 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

区分⼋股精华回答版本和原理底层解释,让⼤家知其然知其所以然,同时⼜能做到⾯试时

的⾼效回答。

结合项⽬(技术派、pmhub)来组织语⾔,让⾯试官最⼤程度感受到你的诚意,⽽不是

机械化的背诵。

修复第⼀版中出现的问题,包括球友们的私信反馈,⽹站留⾔区的评论,以及 GitHub 仓

库中的 issue,让这份⾯试指南更加完善。

增加⼆哥编程星球的球友们拿到的⼀些 offer,对⾯渣逆袭的感谢,以及对简历修改的⼀

些认可,以此来激励⼤家,给⼤家更多信⼼。

优化排版,增加⼿绘图,重新组织答案,使其更加⼝语化,从⽽更贴近⾯试官的预期。

⻓按识别下⾯的⼆维码,关注⼆哥的公众号,回复【222】即可拉取最新版本。

No. 3 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

当然了,请允许我的⼀点点私⼼,那就是星球的 PDF 版本会⽐公众号早⼀个⽉时间,毕竟星

球⽤户都付费过了,我有必要让他们先享受到⼀点点福利。相信⼤家也都能理解,毕竟在线

版是免费的,CDN、服务器、域名、OSS 等等都是需要成本的。

更别说我付出的时间和精⼒了,⼤家觉得有帮助还请给个⼝碑,让你身边的同事、同学都能

受益到。

No. 4 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

我把⼆哥的 Java 进阶之路、JVM 进阶之路、并发编程进阶之路,以及所有⾯渣逆袭的版本都

放进来了,涵盖 Java基础、Java集合、Java并发、JVM、Spring、MyBatis、计算机⽹络、

操作系统、MySQL、Redis、RocketMQ、分布式、微服务、设计模式、Linux 等 16 个⼤的

主题,共有 40 多万字,2000+张⼿绘图,可以说是诚意满满。

展示⼀下暗⿊版本的 PDF 吧,排版清晰,字体优雅,更加适合夜服,晚上看会更舒服⼀点。

No. 5 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

基础

1.并⾏跟并发有什么区别?

并⾏是多核 CPU 上的多任务处理,多个任务在同⼀时间真正地同时执⾏。

并发是单核 CPU 上的多任务处理,多个任务在同⼀时间段内交替执⾏,通过时间⽚轮转

实现交替执⾏,⽤于解决 IO 密集型任务的瓶颈。

No. 6 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

举个例⼦,就好像我们去⻝堂打饭,并⾏就是每个⼈对应⼀个阿姨,同时打饭;⽽并发就是

⼀个阿姨,轮流给每个⼈打饭,假如有个⼈磨磨唧唧,阿姨就会吆喝下⼀个⼈,这样就能提

⾼⻝堂的打饭效率。

你是如何理解线程安全的?

推荐阅读:多线程带来了哪些问题?

如果⼀段代码块或者⼀个⽅法被多个线程同时执⾏,还能够正确地处理共享数据,那么这段

代码块或者这个⽅法就是线程安全的。

No. 7 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

可以从三个要素来确保线程安全:

①、原⼦性:⼀个操作要么完全执⾏,要么完全不执⾏,不会出现中间状态。

可以通过同步关键字 synchronized 或原⼦操作,如 AtomicInteger 来保证原⼦性。

AtomicInteger count = new AtomicInteger(0);

count.incrementAndGet(); // 原⼦操作

②、可⻅性:当⼀个线程修改了共享变量,其他线程能够⽴即看到变化。

No. 8 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

可以通过 volatile 关键字来保证可⻅性。

private volatile String itwanger = "沉默王⼆";

③、有序性:要确保线程不会因为死锁、饥饿、活锁等问题导致⽆法继续执⾏。

No. 9 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

1. Java ⾯试指南(付费)收录的华为 OD ⾯经同学 1 ⼀⾯⾯试原题:对于多线程

编程的了解?

2. Java ⾯试指南(付费)收录的快⼿⾯经同学 1 部⻔主站技术部⾯试原题:你对

线程安全的理解是什么?

memo:2025 年 1 ⽉ 22 ⽇修改⾄此。

2.说说进程和线程的区别?

推荐阅读:进程与线程的区别是什么?

进程说简单点就是我们在电脑上启动的⼀个个应⽤。它是操作系统分配资源的最⼩单位。

线程是进程中的独⽴执⾏单元。多个线程可以共享同⼀个进程的资源,如内存;每个线程都

有⾃⼰独⽴的栈和寄存器。

No. 10 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

如何理解协程?

协程被视为⽐线程更轻量级的并发单元,可以在单线程中实现并发执⾏,由我们开发者显式

调度。

协程是在⽤户态进⾏调度的,避免了线程切换时的内核态开销。

Java ⾃身是不⽀持携程的,我们可以使⽤ Quasar、Kotlin 等框架来实现协程。

fun main() = runBlocking {

launch {

delay(1000L)

println("World!")

}

println("Hello,")

}

线程间是如何进⾏通信的?

原则上可以通过消息传递和共享内存两种⽅法来实现。Java 采⽤的是共享内存的并发模型。

No. 11 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

这个模型被称为 Java 内存模型,简写为 JMM,它决定了⼀个线程对共享变量的写⼊,何时

对另外⼀个线程可⻅。当然了,本地内存是 JMM 的⼀个抽象概念,并不真实存在。

⽤⼀句话来概括就是:共享变量存储在主内存中,每个线程的私有本地内存,存储的是这个

共享变量的副本。

线程 A 与线程 B 之间如要通信,需要要经历 2 个步骤:

线程 A 把本地内存 A 中的共享变量副本刷新到主内存中。

线程 B 到主内存中读取线程 A 刷新过的共享变量,再同步到⾃⼰的共享变量副本中。

No. 12 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

1. Java ⾯试指南(付费)收录的字节跳动商业化⼀⾯的原题:进程和线程区别,

线程共享内存和进程共享内存的区别

2. Java ⾯试指南(付费)收录的⼩⽶春招同学 K ⼀⾯⾯试原题:协程和线程和进

程的区别

3. Java ⾯试指南(付费)收录的字节跳动⾯经同学 1 Java 后端技术⼀⾯⾯试原

题:线程和进程有什么区别?

4. Java ⾯试指南(付费)收录的华为 OD ⾯经同学 1 ⼀⾯⾯试原题:对于多线程

编程的了解?

5. Java ⾯试指南(付费)收录的美团⾯经同学 2 Java 后端技术⼀⾯⾯试原题:进

程和线程的区别?

6. Java ⾯试指南(付费)收录的华为⾯经同学 9 Java 通⽤软件开发⼀⾯⾯试原

题:进程和线程的区别

7. Java ⾯试指南(付费)收录的 ⼩公司⾯经合集好未来测开⾯经同学 3 测开⼀⾯

⾯试原题:进程和线程的区别

8. Java ⾯试指南(付费)收录的招商银⾏⾯经同学 6 招银⽹络科技⾯试原题:进

程和线程的区别?

9. Java ⾯试指南(付费)收录的⽤友⾯试原题:线程和进程的区别

10. Java ⾯试指南(付费)收录的vivo ⾯经同学 10 技术⼀⾯⾯试原题:线程的概

念,线程有哪些状态

No. 13 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

11. Java ⾯试指南(付费)收录的海康威视同学 4⾯试原题:对协程的了解,为什

么协程⽐线程还有更低的资源消耗

memo:2025 年 1 ⽉ 23 ⽇修改⾄此。

3.说说线程有⼏种创建⽅式?

推荐阅读:室友打了⼀把王者就学会了 Java 多线程

有三种,分别是继承 Thread 类、实现 Runnable 接⼝、实现 Callable 接⼝。

第⼀种需要重写⽗类 Thread 的 run() ⽅法,并且调⽤ start() ⽅法启动线程。

class ThreadTask extends Thread {

public void run() {

System.out.println("看完⼆哥的 Java 进阶之路,上岸了!");

}

public static void main(String[] args) {

ThreadTask task = new ThreadTask();

task.start();

}

}

这种⽅法的缺点是,如果 ThreadTask 已经继承了另外⼀个类,就不能再继承 Thread 类了,

因为 Java 不⽀持多重继承。

No. 14 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

第⼆种需要重写 Runnable 接⼝的 run() ⽅法,并将实现类的对象作为参数传递给 Thread

对象的构造⽅法,最后调⽤ start() ⽅法启动线程。

class RunnableTask implements Runnable {

public void run() {

System.out.println("看完⼆哥的 Java 进阶之路,上岸了!");

}

public static void main(String[] args) {

RunnableTask task = new RunnableTask();

Thread thread = new Thread(task);

thread.start();

}

}

这种⽅法的优点是可以避免 Java 的单继承限制,并且更符合⾯向对象的编程思想,因为

Runnable 接⼝将任务代码和线程控制的代码解耦了。

第三种需要重写 Callable 接⼝的 call() ⽅法,然后创建 FutureTask 对象,参数为 Callable

实现类的对象;紧接着创建 Thread 对象,参数为 FutureTask 对象,最后调⽤ start() ⽅

法启动线程。

No. 15 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

class CallableTask implements Callable<String> {

public String call() {

return "看完⼆哥的 Java 进阶之路,上岸了!";

}

public static void main(String[] args) throws ExecutionException,

InterruptedException {

CallableTask task = new CallableTask();

FutureTask<String> futureTask = new FutureTask<>(task);

Thread thread = new Thread(futureTask);

thread.start();

System.out.println(futureTask.get());

}

}

这种⽅法的优点是可以获取线程的执⾏结果。

⼀个 8G 内存的系统最多能创建多少个线程?

推荐阅读:深⼊理解 JVM 的运⾏时数据区

理论上⼤约 8000 个。

创建线程的时候,⾄少需要分配⼀个虚拟机栈,在 64 位操作系统中,默认⼤⼩为 1M,因此

⼀个线程⼤约需要 1M 的内存。

但 JVM、操作系统本身的运⾏就要占⼀定的内存空间,所以实际上可以创建的线程数远⽐

8000 少。

详细解释⼀下。

可以通过 java -XX:+PrintFlagsFinal -version | grep ThreadStackSize 命令查看

JVM 栈的默认⼤⼩。

No. 16 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

其中 ThreadStackSize 的单位是 KB,也就是说默认的 JVM 栈⼤⼩是 1024 KB,也就是

1M。

启动⼀个 Java 程序,你能说说⾥⾯有哪些线程吗?

⾸先是 main 线程,这是程序执⾏的⼊⼝。

然后是垃圾回收线程,它是⼀个后台线程,负责回收不再使⽤的对象。

还有编译器线程,⽐如 JIT,负责把⼀部分热点代码编译后放到 codeCache 中。

No. 17 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

可以通过下⾯的代码进⾏检测:

No. 18 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

class ThreadLister {

public static void main(String[] args) {

// 获取所有线程的堆栈跟踪

Map<Thread, StackTraceElement[]> threads =

Thread.getAllStackTraces();

for (Thread thread : threads.keySet()) {

System.out.println("Thread: " + thread.getName() + " (ID="

+ thread.getId() + ")");

}

}

}

结果如下所示:

Thread: Monitor Ctrl-Break (ID=5)

Thread: Reference Handler (ID=2)

Thread: main (ID=1)

Thread: Signal Dispatcher (ID=4)

Thread: Finalizer (ID=3)

简单解释下:

Thread: main (ID=1) - 主线程,Java 程序启动时由 JVM 创建。

Thread: Reference Handler (ID=2) - 这个线程是⽤来处理引⽤对象的,如软引⽤、

弱引⽤和虚引⽤。负责清理被 JVM 回收的对象。

Thread: Finalizer (ID=3) - 终结器线程,负责调⽤对象的 finalize ⽅法。对象在垃圾

回收器标记为可回收之前,由该线程执⾏其 finalize ⽅法,⽤于执⾏特定的资源释放操

作。

Thread: Signal Dispatcher (ID=4) - 信号调度线程,处理来⾃操作系统的信号,将

它们转发给 JVM 进⾏进⼀步处理,例如响应中断、停⽌等信号。

Thread: Monitor Ctrl-Break (ID=5) - 监视器线程,通常由⼀些特定的 IDE 创建,⽤

于在开发过程中监控和管理程序执⾏或者处理中断。

No. 19 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

1. Java ⾯试指南(付费)收录的字节跳动⾯经同学 1 Java 后端技术⼀⾯⾯试原

题:有多少种实现线程的⽅法?

2. Java ⾯试指南(付费)收录的农业银⾏同学 1 ⾯试原题:实现线程的⽅式和区

3. Java ⾯试指南(付费)收录的农业银⾏⾯经同学 3 Java 后端⾯试原题:说说线

程的创建⽅法

4. Java ⾯试指南(付费)收录的⼩公司⾯经合集同学 1 Java 后端⾯试原题:线程

创建的⽅式?Runable 和 Callable 有什么区别?

5. Java ⾯试指南(付费)收录的阿⾥⾯经同学 5 阿⾥妈妈 Java 后端技术⼀⾯⾯试

原题:⼀个 8G 内存的系统最多能创建多少线程?(奇怪的问题,答了⼀些

pcb、⻚表、虚拟机栈什么的)启动⼀个 Java 程序,你能说说⾥⾯有哪些线程

吗?

6. Java ⾯试指南(付费)收录的招商银⾏⾯经同学 6 招银⽹络科技⾯试原题:如

何创建线程?

7. Java ⾯试指南(付费)收录的百度⾯经同学 1 ⽂⼼⼀⾔ 25 实习 Java 后端⾯试

原题:java 如何创建线程?每次都要创建新线程来实现异步操作,很繁琐,有了

解线程池吗?

8. Java ⾯试指南(付费)收录的美团⾯经同学 4 ⼀⾯⾯试原题:平时怎么使⽤多

线程

memo:2025 年 1 ⽉ 24 ⽇修改⾄此。

4.调⽤ start ⽅法时会执⾏ run ⽅法,那怎么不直接调⽤ run⽅法?

调⽤ start() 会创建⼀个新的线程,并异步执⾏ run() ⽅法中的代码。

直接调⽤ run() ⽅法只是⼀个普通的同步⽅法调⽤,所有代码都在当前线程中执⾏,不会创

建新线程。没有新的线程创建,也就达不到多线程并发的⽬的。

通过敲代码体验⼀下。

No. 20 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

class MyThread extends Thread {

public void run() {

System.out.println(Thread.currentThread().getName());

}

public static void main(String[] args) {

MyThread t1 = new MyThread();

t1.start(); // 正确的⽅式,创建⼀个新线程,并在新线程中执⾏ run()

t1.run(); // 仅在主线程中执⾏ run(),没有创建新线程

}

}

来看输出结果:

main

Thread-0

也就是说,调⽤ start() ⽅法会通知 JVM,去调⽤底层的线程调度机制来启动新线程。

No. 21 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

调⽤ start() 后,线程进⼊就绪状态,等待操作系统调度;⼀旦调度执⾏,线程会执⾏其

run() ⽅法中的代码。

1. Java ⾯试指南(付费)收录的⼩公司⾯经合集同学 1 Java 后端⾯试原题:启动

⼀个线程是 run()还是 start()?

2. Java ⾯试指南(付费)收录的百度⾯经同学 1 ⽂⼼⼀⾔ 25 实习 Java 后端⾯试

原题:java 如何启动多线程,有哪些⽅式?

3. ⼆哥编程星球球友枕云眠美团 AI ⾯试原题:java 线程操作中的 start 和 run ⽅法

区别是什么

memo:2025 年 1 ⽉ 26 ⽇修改⾄此。

5.线程有哪些常⽤的调度⽅法?

⽐如说 start ⽅法⽤于启动线程并让操作系统调度执⾏;sleep ⽅法⽤于让当前线程休眠⼀段

时间;wait ⽅法会让当前线程等待,notify 会唤醒⼀个等待的线程。

No. 22 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

说说wait⽅法和notify⽅法?

当线程 A 调⽤共享对象的 wait() ⽅法时,线程 A 会被阻塞挂起,直到:

线程 B 调⽤了共享对象的 notify() ⽅法或者 notifyAll() ⽅法;

其他线程调⽤线程 A 的 interrupt() ⽅法,导致线程 A 抛出 InterruptedException 异

常。

线程 A 调⽤共享对象的 wait(timeout) ⽅法后,没有在指定的 timeout 时间内被其它线程唤

醒,那么这个⽅法会因为超时⽽返回。

当线程 A 调⽤共享对象的 notify() ⽅法后,会唤醒⼀个在这个共享对象上调⽤ wait 系列

⽅法被挂起的线程。

共享对象上可能会有多个线程在等待,具体唤醒哪个线程是随机的。

No. 23 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

如果调⽤的是 notifyAll ⽅法,会唤醒所有在这个共享变量上调⽤ wait 系列⽅法⽽被挂起的线

程。

说说 sleep ⽅法?

当线程 A 调⽤了 Thread 的 sleep ⽅法后,线程 A 会暂时让出指定时间的执⾏权。

指定的睡眠时间到了后该⽅法会正常返回,接着参与 CPU 调度,获取到 CPU 资源后可以继

续执⾏。

说说yield⽅法?

yield() ⽅法的⽬的是让当前线程让出 CPU 使⽤权,回到就绪状态。但是线程调度器可能

会忽略。

说说interrupt⽅法?

推荐阅读:interrupt ⽅法

interrupt() ⽅法⽤于通知线程停⽌,但不会直接终⽌线程,需要线程⾃⾏处理中断标志。

常与 isInterrupted() 或 Thread.interrupted() 配合使⽤。

Thread thread = new Thread(() -> {

while (!Thread.currentThread().isInterrupted()) {

System.out.println("Running");

}

System.out.println("Interrupted");

});

thread.start();

thread.interrupt(); // 中断线程

说说 stop ⽅法?

stop ⽅法⽤来强制停⽌线程,⽬前已经处于废弃状态,因为 stop ⽅法可能会在不⼀致的状态

下释放锁,破坏对象的⼀致性。

No. 24 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

1. Java ⾯试指南(付费)收录的帆软同学 3 Java 后端⼀⾯的原题:怎么停⽌⼀个

线程,interrupt 和 stop 区别

memo:2025 年 1 ⽉ 27 ⽇修改⾄此。

6.线程有⼏种状态?

6 种。

new 代表线程被创建但未启动;runnable 代表线程处于就绪或正在运⾏状态,由操作系统调

度;blocked 代表线程被阻塞,等待获取锁;waiting 代表线程等待其他线程的通知或中断;

timed_waiting 代表线程会等待⼀段时间,超时后⾃动恢复;terminated 代表线程执⾏完毕,

⽣命周期结束。

No. 25 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

也就是说,线程的⽣命周期可以分为五个主要阶段:新建、就绪、运⾏、阻塞和终⽌。线程

在运⾏过程中会根据状态的变化在这些阶段之间切换。

class ThreadStateExample {

public static void main(String[] args) throws InterruptedException

{

Thread thread = new Thread(() -> {

try {

Thread.sleep(2000); // TIMED_WAITING

synchronized (ThreadStateExample.class) {

ThreadStateExample.class.wait(); // WAITING

}

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

});

No. 26 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

System.out.println("State after creation: " +

thread.getState()); // NEW

thread.start();

System.out.println("State after start: " + thread.getState());

// RUNNABLE

Thread.sleep(500);

System.out.println("State while sleeping: " +

thread.getState()); // TIMED_WAITING

synchronized (ThreadStateExample.class) {

ThreadStateExample.class.notify(); // 唤醒线程

}

thread.join();

System.out.println("State after termination: " +

thread.getState()); // TERMINATED

}

}

⽤⼀个表格来做个总结:

No. 27 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

状态 说明

NEW 当线程被创建后,如通过 new Thread() ,它处于新建状态。此时,线

程已经被分配了必要的资源,但还没有开始执⾏。

RUNNABLE 当调⽤线程的 start() ⽅法后,线程进⼊可运⾏状态。在这个状态下,

线程可能正在运⾏也可能正在等待获取 CPU 时间⽚,具体取决于线程

调度器的调度策略。

BLOCKED 线程在试图获取⼀个锁以进⼊同步块/⽅法时,如果锁被其他线程持

有,线程将进⼊阻塞状态,直到它获取到锁。

WAITING 线程进⼊等待状态是因为调⽤了如下⽅法之⼀: Object.wait() 或

LockSupport.park() 。在等待状态下,线程需要其他线程显式地唤

醒,否则不会⾃动执⾏。

TIME_WAITING 当线程调⽤带有超时参数的⽅法时,如 Thread.sleep(long

millis) 、 Object.wait(long timeout) 或

LockSupport.parkNanos() ,它将进⼊超时等待状态。线程在指定的

等待时间过后会⾃动返回可运⾏状态。

TERMINATED 当线程的 run() ⽅法执⾏完毕后,或者因为⼀个未捕获的异常终⽌了执

⾏,线程进⼊终⽌状态。⼀旦线程终⽌,它的⽣命周期结束,不能再被

重新启动。

如何强制终⽌线程?

第⼀步,调⽤线程的 interrupt() ⽅法,请求终⽌线程。

第⼆步,在线程的 run() ⽅法中检查中断状态,如果线程被中断,就退出线程。

class MyTask implements Runnable {

@Override

public void run() {

while (!Thread.currentThread().isInterrupted()) {

try {

System.out.println("Running...");

Thread.sleep(1000); // 模拟⼯作

} catch (InterruptedException e) {

No. 28 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

// 捕获中断异常后,重置中断状态

Thread.currentThread().interrupt();

System.out.println("Thread interrupted, exiting...");

break;

}

}

}

}

public class Main {

public static void main(String[] args) throws InterruptedException

{

Thread thread = new Thread(new MyTask());

thread.start();

Thread.sleep(3000); // 主线程等待3秒

thread.interrupt(); // 请求终⽌线程

}

}

中断结果:

No. 29 / 228

⾯渣逆袭并发编程篇V2-让天下所有的⾯渣都能逆袭

1. Java ⾯试指南(付费)收录的招商银⾏⾯经同学 6 招银⽹络科技⾯试原题:线

程的⽣命周期和状态?

2. Java ⾯试指南(付费)收录的快⼿同学 2 ⼀⾯⾯试原题:线程有哪些状态?

3. Java ⾯试指南(付费)收录的 OPPO ⾯经同学 1 ⾯试原题:Java⾥线程的⽣命

周期

4. Java ⾯试指南(付费)收录的同学 D ⼩⽶⼀⾯原题:线程的⽣命周期

7.什么是线程上下⽂切换?

线程上下⽂切换是指 CPU 从⼀个线程切换到另⼀个线程执⾏时的过程。

在线程切换的过程中,CPU 需要保存当前线程的执⾏状态,并加载下⼀个线程的上下⽂。

之所以要这样,是因为 CPU 在同⼀时刻只能执⾏⼀个线程,为了实现多线程并发执⾏,需要

不断地在多个线程之间切换。

为了让⽤户感觉多个线程是在同时执⾏的, CPU 资源的分配采⽤了时间⽚轮转的⽅式,线程

在时间⽚内占⽤ CPU 执⾏任务。当线程使⽤完时间⽚后,就会让出 CPU 让其他线程占⽤。

No. 30 / 228

开通会员 本次下载免费

所有资料全部免费下载! 推荐用户付费下载获取返佣积分! 积分可以兑换商品!
一键复制 下载文档 联系客服