Java創(chuàng)建線程的七種方法總結(jié)(全網(wǎng)最全面)
前言
屬于基礎(chǔ)的面試問(wèn)題,一定要能夠回答全哦~
一、繼承Thread,重寫(xiě)run方法
通過(guò)自定義一個(gè)類(這里起名為:MyThread),繼承Thread類,重寫(xiě)run方法,最后在main方法中new出MyThread實(shí)例,調(diào)用這個(gè)實(shí)例的繼承的Thread類的start方法創(chuàng)建一個(gè)線程。
Ps:
1.創(chuàng)建出MyThread實(shí)例,并不代表在系統(tǒng)真的創(chuàng)建一個(gè)線程,只有調(diào)用start方法時(shí),才創(chuàng)建出一個(gè)新的線程,新線程會(huì)執(zhí)行run里的邏輯,直到run里邏輯執(zhí)行完,線程就結(jié)束了;
2.運(yùn)行一次Java程序就啟動(dòng)了一個(gè)進(jìn)程,一個(gè)進(jìn)程里至少會(huì)有一個(gè)線程,這里JVM默認(rèn)創(chuàng)建的線程就是main線程(主線程),main主線程和MyThread創(chuàng)建出來(lái)的新線程是“并發(fā)執(zhí)行”的關(guān)系(并發(fā)+并行),也可以理解為同時(shí)執(zhí)行,各執(zhí)行各的;
3.直接調(diào)用run并沒(méi)有創(chuàng)建線程,只是在原來(lái)的線程中執(zhí)行代碼;
代碼如下:
class MyThread extends Thread { @Override public void run() { System.out.println("繼承Thread,重寫(xiě)run方法創(chuàng)建線程"); } } public class Main { public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); } }
二、實(shí)現(xiàn)Runnable接口,重寫(xiě)run方法
通過(guò)自定義一個(gè)類(這里起名為:MyRunnable)實(shí)現(xiàn)Runnable接口,重寫(xiě)run方法,最后在main方法new出MyRunnable實(shí)例和Thread實(shí)例,最后通過(guò)start方法創(chuàng)建并啟動(dòng)線程。
通俗理解:
這里相當(dāng)于把線程要干的活和線程本身分離開(kāi)了,使用MyRunnable這個(gè)自定義的類來(lái)表示“線程要完成的任務(wù)”,這樣做的目的就是為了“解耦合”,假設(shè)未來(lái)有新的任務(wù)需要線程去執(zhí)行,那么通過(guò)這種方式,代碼改動(dòng)就比較小。
代碼如下:
class MyRunnable implements Runnable { @Override public void run() { System.out.println("實(shí)現(xiàn)Runnable接口,重寫(xiě)run方法"); } } public class Main { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); } }
三、使用匿名內(nèi)部類創(chuàng)建 Thread 子類對(duì)象
直接創(chuàng)建Thread子類,同時(shí)實(shí)例化出一個(gè)對(duì)象,重寫(xiě)run方法,最后通過(guò)start方法創(chuàng)建并啟動(dòng)線程。
代碼如下:
public class Main { public static void main(String[] args) { Thread thread = new Thread() { @Override public void run() { System.out.println("使用匿名內(nèi)部類創(chuàng)建 Thread 子類對(duì)象"); } }; thread.start(); } }
四、使用匿名內(nèi)部類,實(shí)現(xiàn)Runnable接口
通過(guò)使用使用匿名內(nèi)部類,實(shí)現(xiàn)Runnable接口作為T(mén)hread構(gòu)造方法的參數(shù),最后通過(guò)start創(chuàng)建并啟動(dòng)線程;
代碼如下:
public class Main { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("使用匿名內(nèi)部類,實(shí)例Runnable接口作為構(gòu)造參數(shù)"); } }); thread.start(); } }
五、lambda表達(dá)式
lambda本質(zhì)上就是一個(gè)“匿名函數(shù)”,()表示函數(shù)的形參,{}表示函數(shù)體,->特殊語(yǔ)法,表示它是lambda表達(dá)式(->是從C++那里抄來(lái)的)。
代碼如下:
public class Main { public static void main(String[] args) { Thread thread = new Thread(() -> { System.out.println("使用lambda表示創(chuàng)建線程"); }); thread.start(); } }
六、實(shí)現(xiàn)Callable接口
通過(guò)自定義類(這里起名為:MyCallable),實(shí)現(xiàn)Callable接口,重寫(xiě)call方法(call方法可以理解為線程需要執(zhí)行的任務(wù)),并且?guī)в蟹祷刂?,這個(gè)返回表示一個(gè)計(jì)算結(jié)果,如果無(wú)法計(jì)算結(jié)果,則引發(fā)Exception異常,如下源碼英文解釋:
接著創(chuàng)建Callable實(shí)例,使用FutrueTast類包裝Callable對(duì)象,F(xiàn)utureTask是一個(gè)包裝器,需要接收Callable實(shí)例來(lái)創(chuàng)建,并且有兩個(gè)構(gòu)造函數(shù),一個(gè)參數(shù)只有Callable對(duì)象,另一個(gè)參數(shù)不僅有Callable對(duì)象,還有一個(gè)泛型的result參數(shù),詳細(xì)解釋如下源碼:
最后使用FutureTask對(duì)象作為T(mén)hread的構(gòu)造參數(shù),通過(guò)start方法創(chuàng)建并啟動(dòng)線程;
注意:這里可以用get方法獲取線程執(zhí)行后的返回值。
代碼如下:
class MyCallableTest implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("創(chuàng)建線程:" + Thread.currentThread().getName()); return 2; } } public class Main { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<Integer> task = new FutureTask<>(new MyCallableTest()); Thread thread = new Thread(task); thread.start(); System.out.println("創(chuàng)建線程的返回結(jié)果為:" + task.get()); } }
七、使用線程池創(chuàng)建線程
在Java中,線程池的本體叫ThreadPoolExecutor,他的構(gòu)造方法寫(xiě)起來(lái)十分麻煩,為了簡(jiǎn)化構(gòu)造方法,標(biāo)準(zhǔn)庫(kù)就提供了一系列工廠方法,簡(jiǎn)化使用;
什么是工廠模式?
工廠模式,將創(chuàng)建產(chǎn)品實(shí)例的權(quán)利移交工廠,我們不再通過(guò)new來(lái)創(chuàng)建我們所需的對(duì)象,而是通過(guò)工廠來(lái)獲取我們需要的產(chǎn)品。降低了產(chǎn)品使用者與使用者之間的耦合關(guān)系;
也就是說(shuō)這里創(chuàng)建線程池沒(méi)有顯式new,而是通過(guò)Executors這個(gè)靜態(tài)方法newCaChedThreadPool來(lái)完成的;
常見(jiàn)用法:
線程池的單純使用很簡(jiǎn)單,使用submit方法,把任務(wù)提交到線程池中即可,線程池中會(huì)有線程來(lái)完成這些任務(wù);
代碼如下:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Pool { public static void main(String[] args) { ExecutorService pool = Executors.newCachedThreadPool(); pool.submit(new Runnable() { @Override public void run() { //執(zhí)行業(yè)務(wù)邏輯 for(int i = 1; i <= 100; i++) { System.out.println("線程:" + Thread.currentThread().getName() + "執(zhí)行了任務(wù)" + i + "~"); } } }); pool.submit(new Runnable() { @Override public void run() { //執(zhí)行業(yè)務(wù)邏輯 for(int i = 101; i <= 200; i++) { System.out.println("線程:" + Thread.currentThread().getName() + "執(zhí)行了任務(wù)" + i + "~"); } } }); pool.submit(new Runnable() { @Override public void run() { //執(zhí)行業(yè)務(wù)邏輯 for(int i = 201; i <= 300; i++) { System.out.println("線程:" + Thread.currentThread().getName() + "執(zhí)行了任務(wù)" + i + "~"); } } }); } }
當(dāng)任務(wù)量達(dá)到一定程度,一個(gè)線程忙不過(guò)來(lái)時(shí),就會(huì)發(fā)現(xiàn)其他線程也來(lái)幫忙遼~
總結(jié)
到此這篇關(guān)于Java創(chuàng)建線程的七種方法總結(jié)的文章就介紹到這了,更多相關(guān)Java創(chuàng)建線程方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java枚舉類的屬性、方法和構(gòu)造方法應(yīng)用實(shí)戰(zhàn)
這篇文章主要介紹了java枚舉類的屬性、方法和構(gòu)造方法應(yīng)用,結(jié)合實(shí)例形式分析了java枚舉類的定義、構(gòu)造及相關(guān)應(yīng)用操作技巧,需要的朋友可以參考下2019-08-08IDEA 2020.1 搜索不到Chinese (Simplified) Language
小編在安裝中文插件時(shí)遇到IDEA 2020.1 搜索不到Chinese ​(Simplified)​ Language Pack EAP,無(wú)法安裝的問(wèn)題,本文給大家分享我的解決方法,感興趣的朋友一起看看吧2020-04-04MyBatis使用annonation定義類型映射的簡(jiǎn)易用法示例
這篇文章主要介紹了MyBatis使用annonation定義類型映射的簡(jiǎn)易用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09Java中main函數(shù)的String[]?args用法舉例詳解
這篇文章主要給大家介紹了關(guān)于Java中main函數(shù)的String[]?args用法的相關(guān)資料,JAVA類中main函數(shù)的參數(shù)String[]?args指的是運(yùn)行時(shí)給main函數(shù)傳遞的參數(shù),文中通過(guò)圖文以及代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12