Java 多線程的創(chuàng)建
1. 前言
本節(jié)內(nèi)容重點需要掌握 Java 多線程的三種創(chuàng)建方式,具體內(nèi)容如下:
- Java 線程類 Thread 繼承結(jié)構(gòu),這是 JDK Thread 源碼的類結(jié)構(gòu),是了解 Thread 類的第一步;
- 掌握多線程的三種創(chuàng)建方式,這是本節(jié)的重點內(nèi)容。本節(jié)所有內(nèi)容都是圍繞改話題進行的講解;
- 了解多線程不同創(chuàng)建方式的優(yōu)劣,不同的創(chuàng)建方式有自己的優(yōu)勢和劣勢,本節(jié)還會推薦同學(xué)使用第二種接口實現(xiàn)的創(chuàng)建方式;
- 掌握 Thread 類常用方法,這也是本節(jié)的重點內(nèi)容,其常用方法使我們開發(fā)過程中經(jīng)常涉及到的,必須要熟記于心;
- Thread 類編程實驗實戰(zhàn),學(xué)習(xí)完多線程的創(chuàng)建方式,我們需要進行實戰(zhàn)代碼鞏固本節(jié)的內(nèi)容。
2. Thread 類結(jié)構(gòu)介紹
介紹: 位于 java.lang 包下的 Thread 類是非常重要的線程類。學(xué)習(xí) Thread 類的使用是學(xué)習(xí)多線程并發(fā)編程的基礎(chǔ)。它實現(xiàn)了 Runnable 接口,其包集成結(jié)構(gòu)如下圖所示。
3. 多線程的三種創(chuàng)建方式
Java 多線程有 3 種創(chuàng)建方式如下:
- 方式一:繼承 Thread 類的方式創(chuàng)建線程;
- 方式二:實現(xiàn) java.lang.Runnable 接口;
- 方式三:實現(xiàn) Callable 接口。
在接下來的內(nèi)容中,會詳細的對這 3 種創(chuàng)建方式進行詳細的講解。
4. 多線程實現(xiàn)之繼承 Thread 類
實現(xiàn)步驟:
- 步驟 1:繼承 Thread 類 extends Thread;
- 步驟 2:復(fù)寫 run () 方法,run () 方法是線程具體邏輯的實現(xiàn)方法。
實例:
/**
* 方式一:繼承Thread類的方式創(chuàng)建線程
*/
public class ThreadExtendTest extends Thread{ //步驟 1
@Override
public void run() { //步驟 2
//run方法內(nèi)為具體的邏輯實現(xiàn)
System.out.println("create thread by thread extend");
}
public static void main(String[] args) {
new ThreadExtendTest(). start();
}
}
5. 多線程實現(xiàn)之實現(xiàn) Runnable 接口
Tips:由于 Java 是面向接口編程,且可進行多接口實現(xiàn),相比 Java 的單繼承特性更加靈活,易于擴展,所以相比方式一,更推薦使用方式二進行線程的創(chuàng)建。
實現(xiàn)步驟:
- 步驟 1:實現(xiàn) Runnable 接口,implements Runnable;
- 步驟 2:復(fù)寫 run () 方法,run () 方法是線程具體邏輯的實現(xiàn)方法。
實例:
/**
* 方式二:實現(xiàn)java.lang.Runnable接口
*/
public class ThreadRunnableTest implements Runnable{//步驟 1
@Override
public void run() {//步驟 2
//run方法內(nèi)為具體的邏輯實現(xiàn)
System.out.println("create thread by runnable implements");
}
public static void main(String[] args) {
new Thread(new ThreadRunnableTest()). start();
}
}
6. 多線程實現(xiàn)之實現(xiàn) Callable 接口
Tips:方式一與方式二的創(chuàng)建方式都是復(fù)寫 run 方法,都是 void 形式的,沒有返回值。但是對于方式三來說,實現(xiàn) Callable 接口,能夠有返回值類型。
實現(xiàn)步驟:
- 步驟 1:實現(xiàn) Callable 接口,implements Callable;
- 步驟 2:復(fù)寫 call () 方法,call () 方法是線程具體邏輯的實現(xiàn)方法。
實例:
/**
* 方式三:實現(xiàn)Callable接口
*/
public class ThreadCallableTest implements Callable<String> {//步驟 1
@Override
public String call() throws Exception { //步驟 2
//call 方法的返回值類型是 String
//call 方法是線程具體邏輯的實現(xiàn)方法
return "create thread by implements Callable";
}
public static void main(String[] args) throws ExecutionException, InterruptedException{
FutureTask<String> future1 = new FutureTask<String>(new ThreadCallableTest());
Thread thread1 = new Thread(future1);
thread1. start();
System.out.println(future1.get());
}
}
7. 匿名內(nèi)部類創(chuàng)建 Thread
首先確認,這并不是線程創(chuàng)建的第四種方式,先來看如何創(chuàng)建。
實例:
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("通過匿名內(nèi)部類創(chuàng)建Thread");
}
});
我們從代碼中可以看出,還是進行了一個 Runnable 接口的使用,所以這并不是新的 Thread 創(chuàng)建方式,只不過是通過方式二實現(xiàn)的一個內(nèi)部類創(chuàng)建。
Tips: 在后續(xù)章節(jié)講解 join 方法如何使用 的時候,我們會采用匿名內(nèi)部類的方式進行多線程的創(chuàng)建。
8. Thread 類的常用方法介紹
方法 | 作用 |
---|---|
start() | 啟動當(dāng)前的線程,調(diào)用當(dāng)前線程的 run ()。 |
run() | 通常需要重寫 Thread 類中的此方法,將創(chuàng)建要執(zhí)行的操作聲明在此方法中。 |
currentThread() | 靜態(tài)方法,返回代碼執(zhí)行的線程。 |
getName() | 獲取當(dāng)前線程的名字。 |
setName() | 設(shè)置當(dāng)前線程的名字。 |
sleep(long millitime) | 讓當(dāng)前進程睡眠指定的毫秒數(shù),在指定時間內(nèi),線程是阻塞狀態(tài)。 |
isAlive() | 判斷進程是否存活。 |
wait() | 線程等待。 |
notify() | 線程喚醒。 |
9. Thread 編程測驗實驗
實驗?zāi)康?/strong>:對 Thread 的創(chuàng)建方式進行練習(xí),鞏固本節(jié)重點內(nèi)容,并在練習(xí)的過程中,使用常用的 start 方法和 sleep 方法以及 線程的 setName 方法。
實驗步驟:
- 使用 Runnable 接口創(chuàng)建兩條線程 :t1 和 t2;
- 請設(shè)置線程 t1 和 t2 的線程名稱分別為 “ThreadOne” 和 “ThreadTwo”;
- 線程 t1 執(zhí)行完 run () 方法后,線程睡眠 5 秒;
- 線程 t2 執(zhí)行完 run () 方法后,線程睡眠 1 秒。
請先自行實現(xiàn),并將結(jié)果與所提供的答案進行復(fù)核。
public class ThreadTest implements Runnable{
@Override
public void run() {
System.out.println("線程:"+Thread.currentThread()+" 正在執(zhí)行...");
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new ThreadTest());
t1.setName("ThreadOne");
Thread t2 = new Thread(new ThreadTest());
t2.setName("ThreadTwo");
t1. start();
t1.sleep(5000);
t2. start();
t1.sleep(1000);
System.out.println("線程執(zhí)行結(jié)束。");
}
}
執(zhí)行結(jié)果:
線程:Thread[ThreadOne,5,main] 正在執(zhí)行...
線程:Thread[ThreadTwo,5,main] 正在執(zhí)行...
線程執(zhí)行結(jié)束。
Tips: 該測驗主要針對線程的創(chuàng)建方式以及線程的執(zhí)行 start 方法的測驗,并附帶進行了線程 setName 和線程 sleep 方法的使用。對于線程其他常用方法的使用如 wait 方法等,會在后續(xù)小節(jié)進行詳細講解。
10. 小結(jié)
本節(jié)課程的重中之重就是掌握線程的 3 中創(chuàng)建方式以及 Thread 類常用方法的使用,一定要掌握并吃透。
線程 Thread 的創(chuàng)建方式以及執(zhí)行方式是學(xué)習(xí)多線程并發(fā)的前提條件,我們在使用無返回值的多線程創(chuàng)建方式時,推薦使用方式二進行多線程的創(chuàng)建。如果針對具體的業(yè)務(wù)場景需要使用多線程執(zhí)行結(jié)果的返回值,那我們需要使用方式三進行線程的創(chuàng)建。