@@ -12,24 +12,27 @@ tags:
1212
1313<!-- TOC depthFrom:2 depthTo:3 -->
1414
15- * [ 线程生命周期] ( #线程生命周期 )
16- * [ 创建线程] ( #创建线程 )
17- * [ 继承 Thread 类] ( #继承-thread-类 )
18- * [ 实现 Runnable 接口] ( #实现-runnable-接口 )
19- * [ 通过 Callable 接口和 Future 接口] ( #通过-callable-接口和-future-接口 )
20- * [ 三种创建线程方式对比] ( #三种创建线程方式对比 )
21- * [ Thread 中的重要方法] ( #thread-中的重要方法 )
22- * [ 设置/获取线程名称] ( #设置获取线程名称 )
23- * [ 判断线程是否启动] ( #判断线程是否启动 )
24- * [ 中断线程] ( #中断线程 )
25- * [ 守护线程] ( #守护线程 )
26- * [ 设置/获取线程优先级] ( #设置获取线程优先级 )
27- * [ 线程的强制执行] ( #线程的强制执行 )
28- * [ 线程的休眠] ( #线程的休眠 )
29- * [ 线程的礼让] ( #线程的礼让 )
15+ * [ 线程简介] ( #线程简介 )
16+ * [ 什么是线程] ( #什么是线程 )
17+ * [ 线程生命周期] ( #线程生命周期 )
18+ * [ 启动和终止线程] ( #启动和终止线程 )
19+ * [ 构造线程] ( #构造线程 )
20+ * [ 继承 Thread 类] ( #继承-thread-类 )
21+ * [ 实现 Runnable 接口] ( #实现-runnable-接口 )
22+ * [ 实现 Callable 接口] ( #实现-callable-接口 )
23+ * [ 三种创建线程方式对比] ( #三种创建线程方式对比 )
24+ * [ Thread 中的重要方法] ( #thread-中的重要方法 )
25+ * [ 设置/获取线程名称] ( #设置获取线程名称 )
26+ * [ 判断线程是否启动] ( #判断线程是否启动 )
27+ * [ 中断线程] ( #中断线程 )
28+ * [ 守护线程] ( #守护线程 )
29+ * [ 设置/获取线程优先级] ( #设置获取线程优先级 )
30+ * [ 线程的强制执行] ( #线程的强制执行 )
31+ * [ 线程的休眠] ( #线程的休眠 )
3032 * [ 线程的终止] ( #线程的终止 )
31- * [ Object 中的并发方法 ] ( #object-中的并发方法 )
33+ * [ 线程间通信 ] ( #线程间通信 )
3234 * [ wait/notify/notifyAll] ( #waitnotifynotifyall )
35+ * [ 线程的礼让] ( #线程的礼让 )
3336* [ FAQ] ( #faq )
3437 * [ start() 和 run() 有什么区别?可以直接调用 Thread 类的 run() 方法么?] ( #start-和-run-有什么区别可以直接调用-thread-类的-run-方法么 )
3538 * [ sleep()、yield()、join() 方法有什么区别?为什么 sleep()和 yield()方法是静态的?] ( #sleepyieldjoin-方法有什么区别为什么-sleep和-yield方法是静态的 )
@@ -42,11 +45,24 @@ tags:
4245
4346<!-- /TOC -->
4447
45- ## 线程生命周期
48+ ## 线程简介
49+
50+ ### 什么是线程
51+
52+ 现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process),在一个进程里可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。
53+
54+ ### 线程生命周期
55+
56+ <p align =" center " >
57+ <img src =" https://raw.githubusercontent.com/dunwu/javase-notes/master/images/concurrent/thread-state.png " >
58+ </p >
59+
60+ 线程的生命周期有 6 种不同的状态,在给定的一个时刻,线程只能处于其中的一个状态。
61+
62+ 以下是 6 种状态的说明,以及状态间的联系。
4663
4764* 开始(New):如果创建 Thread 类的实例,但在调用 start() 方法之前,线程处于新状态。
4865* 可运行(Runnable):线程对象创建后,其他线程(比如 main 线程)调用了该对象的 start()方法。此状态意味着,线程已经准备好了,一旦被线程调度器分配了 CPU 时间片,就可以运行线程。
49- * 运行(Running):可运行状态(Runnable)的线程获得了 cpu 时间片(timeslice),执行程序代码。
5066* 定时等待(Timed waiting):定时等待是在指定等待时间内等待的线程状态。调用以下方法,线程会进入定时等待状态:
5167 * Thread.sleep(sleeptime)
5268 * Object.wait(timeout)
@@ -60,25 +76,25 @@ tags:
6076* 阻塞(Blocked):阻塞状态。线程阻塞的线程状态等待监视器锁定。处于阻塞状态的线程正在等待监视器锁定,以便在调用 Object.wait 之后输入同步块/方法或重新输入同步块/方法。
6177* 终止(Terminated):线程 run()、main() 方法执行结束,或者因异常退出了 run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
6278
63- 线程状态切换如下图所示:
79+ ## 启动和终止线程
6480
65- <p align =" center " >
66- <img src =" https://raw.githubusercontent.com/dunwu/javase-notes/master/images/concurrent/thread-states.png " alt =" thread-states " >
67- </p >
81+ ### 构造线程
6882
69- ## 创建线程
83+ 构造线程主要有三种方式
7084
71- 创建线程主要有三种方式
85+ * 继承 ` Thread ` 类
86+ * 实现 ` Runnable ` 接口
87+ * 实现 ` Callable ` 接口
7288
73- * 继承 Thread 类
74- * 实现 Runnable 接口
75- * 通过 Callable 接口和 Future 接口
89+ #### 继承 Thread 类
7690
77- ### 继承 Thread 类
91+ 通过继承 Thread 类构造线程的步骤:
7892
79- * 定义 Thread 类的子类,并重写该类的 run 方法,该 run 方法的方法体就代表了线程要完成的任务。因此把 run()方法称为执行体。
93+ * 定义 Thread 类的子类,并重写该类的 run() 方法,该 run() 方法的方法体就代表了线程要完成的任务。因此把 run() 方法称为执行体。
8094* 创建 Thread 子类的实例,即创建了线程对象。
81- * 调用线程对象的 start()方法来启动该线程。
95+ * 调用线程对象的 start() 方法来启动该线程。
96+
97+ 示例:
8298
8399``` java
84100public class ThreadDemo02 {
@@ -110,11 +126,15 @@ public class ThreadDemo02 {
110126}
111127```
112128
113- ### 实现 Runnable 接口
129+ #### 实现 Runnable 接口
130+
131+ 通过实现 Runnable 接口构造线程的步骤:
114132
115- * 定义 Runnable 接口的实现类,并重写该接口的 run()方法,该 run()方法的方法体同样是该线程的线程执行体。
133+ * 定义 Runnable 接口的实现类,并重写该接口的 run() 方法,该 run() 方法的方法体同样是该线程的线程执行体。
116134* 创建 Runnable 实现类的实例,并依此实例作为 Thread 的 target 来创建 Thread 对象,该 Thread 对象才是真正的线程对象。
117- * 调用线程对象的 start()方法来启动该线程。
135+ * 调用线程对象的 start() 方法来启动该线程。
136+
137+ 示例:
118138
119139``` java
120140public class RunnableDemo {
@@ -147,12 +167,16 @@ public class RunnableDemo {
147167}
148168```
149169
150- ### 通过 Callable 接口和 Future 接口
170+ #### 实现 Callable 接口
151171
152- * 创建 Callable 接口的实现类,并实现 call()方法,该 call()方法将作为线程执行体,并且有返回值。
153- * 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call()方法的返回值。
172+ 通过实现 Callable 接口构造线程的步骤:
173+
174+ * 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
175+ * 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
154176* 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
155- * 调用 FutureTask 对象的 get()方法来获得子线程执行结束后的返回值
177+ * 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
178+
179+ 示例:
156180
157181``` java
158182public class CallableAndFutureDemo {
@@ -171,12 +195,12 @@ public class CallableAndFutureDemo {
171195}
172196```
173197
174- ### 三种创建线程方式对比
198+ #### 三种创建线程方式对比
175199
176- * 实现 Runnable 接口优于继承 Thread 类,因为实现接口更便于扩展;
177- * 实现 Runnable 接口的线程没有返回值;而使用 Callable Future 方式可以让线程有返回值 。
200+ * ** 实现 Runnable 接口优于继承 Thread 类** ,因为实现接口方式更便于扩展类。
201+ * 实现 Runnable 接口的线程没有返回值;而 ** 实现 Callable 接口的线程有返回值 ** 。
178202
179- ## Thread 中的重要方法
203+ ### Thread 中的重要方法
180204
181205* ` run ` - 线程的执行实体。
182206* ` start ` - 线程的启动方法。
@@ -189,7 +213,7 @@ public class CallableAndFutureDemo {
189213* ` Thread.sleep ` - 使用 Thread.sleep() 方法即可实现休眠。
190214* ` Thread.yield ` - 可以使用 Thread.yield() 方法将一个线程的操作暂时让给其他线程执行。
191215
192- ### 设置/获取线程名称
216+ #### 设置/获取线程名称
193217
194218在 Thread 类中可以通过 ` setName() ` 、 ` getName() ` 来设置、获取线程名称。
195219
@@ -217,7 +241,7 @@ public class ThreadNameDemo {
217241}
218242```
219243
220- ### 判断线程是否启动
244+ #### 判断线程是否启动
221245
222246在 Thread 类中可以通过 ` isAlive() ` 来判断线程是否启动。
223247
@@ -250,7 +274,7 @@ public class ThreadAliveDemo {
250274}
251275```
252276
253- ### 中断线程
277+ #### 中断线程
254278
255279当一个线程运行时,另一个线程可以直接通过 ` interrupt() ` 方法中断其运行状态。
256280
@@ -287,7 +311,7 @@ public class ThreadInterruptDemo {
287311}
288312```
289313
290- ### 守护线程
314+ #### 守护线程
291315
292316在 Java 程序中,只要前台有一个线程在运行,则整个 Java 进程就不会消失,所以此时可以设置一个守护线程,这样即使 Java 进程结束了,此守护线程依然会继续执行。可以使用 ` setDaemon() ` 方法设置线程为守护线程;可以使用 ` isDaemon() ` 方法判断线程是否为守护线程。
293317
@@ -313,7 +337,7 @@ public class ThreadDaemonDemo {
313337}
314338```
315339
316- ### 设置/获取线程优先级
340+ #### 设置/获取线程优先级
317341
318342在 Java 中,所有线程在运行前都会保持在就绪状态,那么此时,哪个线程优先级高,哪个线程就有可能被先执行。
319343
@@ -357,7 +381,7 @@ public class ThreadPriorityDemo {
357381}
358382```
359383
360- ### 线程的强制执行
384+ #### 线程的强制执行
361385
362386在线程操作中,可以使用 ` join() ` 方法让一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等待此线程完成之后才可以继续执行。
363387
@@ -392,7 +416,7 @@ public class ThreadJoinDemo {
392416}
393417```
394418
395- ### 线程的休眠
419+ #### 线程的休眠
396420
397421直接使用 ` Thread.sleep() ` 方法即可实现休眠。
398422
@@ -428,40 +452,6 @@ public class ThreadSleepDemo {
428452}
429453```
430454
431- ### 线程的礼让
432-
433- 在线程操作中,可以使用 ` Thread.yield() ` 方法将一个线程的操作暂时让给其他线程执行。
434-
435- ``` java
436- public class ThreadYieldDemo {
437-
438- public static void main (String [] args ) {
439- MyThread t = new MyThread ();
440- new Thread (t, " 线程A" ). start();
441- new Thread (t, " 线程B" ). start();
442- }
443-
444- static class MyThread implements Runnable {
445-
446- @Override
447- public void run () {
448- for (int i = 0 ; i < 5 ; i++ ) {
449- try {
450- Thread . sleep(1000 );
451- } catch (Exception e) {
452- e. printStackTrace();
453- }
454- System . out. println(Thread . currentThread(). getName() + " 运行,i = " + i);
455- if (i == 2 ) {
456- System . out. print(" 线程礼让:" );
457- Thread . yield();
458- }
459- }
460- }
461- }
462- }
463- ```
464-
465455### 线程的终止
466456
467457Thread 中的 stop 方法有缺陷,已废弃。
@@ -500,14 +490,16 @@ public class ThreadStopDemo02 {
500490}
501491```
502492
503- ## Object 中的并发方法
493+ ## 线程间通信
494+
495+ ### wait/notify/notifyAll
496+
497+ wait、notify、notifyAll 是 Object 类中的方法。
504498
505499* ` wait ` - 线程自动释放其占有的对象锁,并等待 notify。
506500* ` notify ` - 唤醒一个正在 wait 当前对象锁的线程,并让它拿到对象锁。
507501* ` notifyAll ` - 唤醒所有正在 wait 前对象锁的线程。
508502
509- ### wait/notify/notifyAll
510-
511503生产者、消费者示例:
512504
513505``` java
@@ -589,6 +581,41 @@ public class ThreadWaitNotifyDemo02 {
589581}
590582```
591583
584+
585+ ### 线程的礼让
586+
587+ 在线程操作中,可以使用 ` Thread.yield() ` 方法将一个线程的操作暂时让给其他线程执行。
588+
589+ ``` java
590+ public class ThreadYieldDemo {
591+
592+ public static void main (String [] args ) {
593+ MyThread t = new MyThread ();
594+ new Thread (t, " 线程A" ). start();
595+ new Thread (t, " 线程B" ). start();
596+ }
597+
598+ static class MyThread implements Runnable {
599+
600+ @Override
601+ public void run () {
602+ for (int i = 0 ; i < 5 ; i++ ) {
603+ try {
604+ Thread . sleep(1000 );
605+ } catch (Exception e) {
606+ e. printStackTrace();
607+ }
608+ System . out. println(Thread . currentThread(). getName() + " 运行,i = " + i);
609+ if (i == 2 ) {
610+ System . out. print(" 线程礼让:" );
611+ Thread . yield();
612+ }
613+ }
614+ }
615+ }
616+ }
617+ ```
618+
592619## FAQ
593620
594621### start() 和 run() 有什么区别?可以直接调用 Thread 类的 run() 方法么?
@@ -661,7 +688,7 @@ Java 的每个对象中都有一个锁(monitor,也可以成为监视器) 并
661688* [ Java 并发编程实战] ( https://item.jd.com/10922250.html )
662689* [ Java 并发编程的艺术] ( https://item.jd.com/11740734.html )
663690* https://stackoverflow.com/questions/27406200/visualvm-thread-states
664- * https://docs.oracle.com/javase/1.5.0 /docs/api/java/lang/Thread.State .html
691+ * https://docs.oracle.com/javase/8 /docs/api/index .html
665692* https://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example
666693* http://www.importnew.com/14958.html
667694* https://blog.csdn.net/xiangwanpeng/article/details/54972952
0 commit comments