154154参考资料:
155155
156156- 《Java并发编程实战》
157- - 【慕课网】Java并发编程与高并发解决方案
158- - 【龙果学院】Java并发编程原理与实战
159157
160158
161159
162160# 第一部分:并发编程
163161
164162## 1. 线程状态转换
165163
166- <div align =" center " > <img src =" https://github.com/CyC2018/Interview-Notebook/raw/master/pics/ ace830df-9919-48ca-91b5-60b193f593d2.png" width =" " /></div >< br / >
164+ <div align =" center " > <img src =" assets/ ace830df-9919-48ca-91b5-60b193f593d2.png" width =" " /></div >
167165
168166### 新建(New)
169167
177175
178176### 阻塞(Blocking)
179177
180- 这个状态下,是在多个线程有同步操作的场景,比如正在等待另一个线程的synchronized 块的执行释放,或者可重入的 synchronized块里别人调用wait () 方法,也就是线程在等待进入临界区。
178+ 这个状态下,是在多个线程有同步操作的场景,比如正在等待另一个线程的 synchronized 块的执行释放,或者可重入的 synchronized 块里别人调用 wait () 方法,也就是线程在等待进入临界区。
181179
182180阻塞可以分为:等待阻塞,同步阻塞,其他阻塞
183181
195193
196194无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。
197195
198- 调用 Thread.sleep() 方法使线程进入限期等待状态时,常常用“** 使一个线程睡眠** ”进行描述。
196+ 调用 Thread.sleep() 方法使线程进入限期等待状态时,常常用 “** 使一个线程睡眠** ” 进行描述。
199197
200- 调用 Object.wait() 方法使线程进入限期等待或者无限期等待时,常常用“** 挂起一个线程** ”进行描述。
198+ 调用 Object.wait() 方法使线程进入限期等待或者无限期等待时,常常用 “** 挂起一个线程** ” 进行描述。
201199
202200** 睡眠和挂起** 是用来描述** 行为** ,而** 阻塞** 和等待用来描述** 状态** 。
203201
213211
214212### 死亡(Terminated)
215213
216- - 线程因为run方法正常退出而自然死亡
217- - 因为一个没有捕获的异常终止了run方法而意外死亡
214+ - 线程因为 run 方法正常退出而自然死亡
215+ - 因为一个没有捕获的异常终止了 run 方法而意外死亡
218216
219217
220218
@@ -313,10 +311,8 @@ public static void main(String[] args) {
313311### 三种方式的区别
314312
315313- 实现 Runnable 接口可以避免 Java 单继承特性而带来的局限;增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的;适合多个相同程序代码的线程区处理同一资源的情况。
316- - 继承 Thread 类和实现 Runnable 方法启动线程都是使用start方法,然后 JVM 虚拟机将此线程放到就绪队列中,如果有处理机可用,则执行 run 方法。
317- - 实现 Callable 接口要实现 call 方法,并且线程执行完毕后会有返回值。其他的两种都是重写 run 方法,没有返回值。
318-
319-
314+ - 继承 Thread 类和实现 Runnable 方法启动线程都是使用 start() 方法,然后 JVM 虚拟机将此线程放到就绪队列中,如果有处理机可用,则执行 run() 方法。
315+ - 实现 Callable 接口要实现 call() 方法,并且线程执行完毕后会有返回值。其他的两种都是重写 run() 方法,没有返回值。
320316
321317
322318
@@ -346,10 +342,10 @@ public static void main(String[] args) {
346342
347343** 为什么引入Executor线程池框架?**
348344
349- new Thread()的缺点
345+ new Thread() 的缺点
350346
351- - 每次new Thread()耗费性能
352- - 调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。
347+ - 每次 new Thread() 耗费性能
348+ - 调用 new Thread() 创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。
353349- 不利于扩展,比如如定时执行、定期执行、线程中断
354350
355351采用线程池的优点
@@ -362,17 +358,17 @@ new Thread()的缺点
362358
363359### Daemon(守护线程)
364360
365- Java 中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)
361+ Java 中有两类线程:User Thread (用户线程)、Daemon Thread (守护线程)
366362
367- 用户线程即运行在前台的线程,而守护线程是运行在后台的线程。 守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通、非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程。当 VM 检测仅剩一个守护线程,而用户线程都已经退出运行时,VM就会退出 ,因为没有如果没有了被守护这,也就没有继续运行程序的必要了。如果有非守护线程仍然存活,VM 就不会退出。
363+ 用户线程即运行在前台的线程,而守护线程是运行在后台的线程。 守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通、非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程。当 JVM 检测仅剩一个守护线程,而用户线程都已经退出运行时,JVM 就会退出 ,因为没有如果没有了被守护这,也就没有继续运行程序的必要了。如果有非守护线程仍然存活,JVM 就不会退出。
368364
369365守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程。用户可以用 Thread 的 setDaemon(true) 方法设置当前线程为守护线程。
370366
371367虽然守护线程可能非常有用,但必须小心确保其他所有非守护线程消亡时,不会由于它的终止而产生任何危害。因为你不可能知道在所有的用户线程退出运行前,守护线程是否已经完成了预期的服务任务。一旦所有的用户线程退出了,虚拟机也就退出运行了。 因此,不要在守护线程中执行业务逻辑操作(比如对数据的读写等)。
372368
373369 ** 另外有几点需要注意:**
374370
375- - setDaemon(true)必须在调用线程的 start()方法之前设置,否则会跑出 IllegalThreadStateException 异常。
371+ - setDaemon(true) 必须在调用线程的 start() 方法之前设置,否则会跑出 IllegalThreadStateException 异常。
376372- 在守护线程中产生的新线程也是守护线程。
377373- 不要认为所有的应用都可以分配给守护线程来进行服务,比如读写操作或者计算逻辑。
378374
@@ -415,7 +411,7 @@ public void run() {
415411
416412### yield()
417413
418- 对静态方法 Thread.yield() 的调用声明了当前线程已经完成了生命周期中最重要的部分 ,可以切换给其它线程来执行。该方法只是对线程调度器的一个建议,而且也只是建议具有相同优先级的其它线程可以运行。
414+ 对静态方法 Thread.yield() 的调用声明了 ** 当前线程已经完成了生命周期中最重要的部分 ** ,可以切换给其它线程来执行。该方法只是对线程调度器的一个建议,而且也只是建议具有相同优先级的其它线程可以运行。
419415
420416``` java
421417public void run() {
@@ -657,7 +653,6 @@ public void func() {
657653
658654``` java
659655public class SynchronizedExample {
660-
661656 public void func2 () {
662657 synchronized (SynchronizedExample . class) {
663658 for (int i = 0 ; i < 10 ; i++ ) {
0 commit comments