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