Java并發(fā)編程創(chuàng)建并運(yùn)行線程的方法對(duì)比
一、創(chuàng)建并運(yùn)行線程的五種方法
第一種:繼承Thread類
這種方式是最基礎(chǔ)的一種方式,學(xué)過(guò)java的朋友都知道,不做贅述。需要注意的是:覆蓋實(shí)現(xiàn)使用的是run方法,運(yùn)行線程是start方法。
public class FirstWay extends Thread { @Override public void run() { System.out.println("第一種實(shí)現(xiàn)線程的方式:繼承Thread類"); } //模擬測(cè)試 public static void main(String[] args) { new FirstWay().start(); } }
第二種:實(shí)現(xiàn)Runnable接口
第二種實(shí)現(xiàn)方式仍然很基礎(chǔ),繼承Runnable接口,重寫(xiě)run方法實(shí)現(xiàn)線程運(yùn)行邏輯。需要注意的:運(yùn)行線程需要套一層new Thread
。
public class SecondWay implements Runnable{ @Override public void run() { System.out.println("第二種實(shí)現(xiàn)線程的方式:實(shí)現(xiàn)Runnable接口"); } //模擬測(cè)試 public static void main(String[] args) { new Thread(new SecondWay()).start(); } }
第三種:實(shí)現(xiàn)Callable接口
第三種方式是實(shí)現(xiàn)Callable接口,Callable接口與Runable接口都能實(shí)現(xiàn)線程。
public class ThirdWay implements Callable<String> { @Override public String call() throws Exception { System.out.println("第三種實(shí)現(xiàn)線程的方式:實(shí)現(xiàn)Callable接口"); return "Callable接口帶返回值,可以拋出異常"; } //模擬測(cè)試 public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> futureTask = new FutureTask<>(new ThirdWay()); new Thread(futureTask).start(); //阻塞方法,獲取call方法返回值 System.out.println(futureTask.get()); //打?。篊allable接口帶返回值,可以拋出異常 } }
區(qū)別如下:
- Callable接口實(shí)現(xiàn)線程方法是call, Runable接口實(shí)現(xiàn)線程方法是run
- Callable有返回值, Runable接口不能有返回值
- Callable接口方法call返回值可以設(shè)置泛型,如下例子中使用String數(shù)據(jù)類型
- Callable接口方法call方法可以拋出異常,Runable接口run方法不可以拋出異常
- Callable接口方法通過(guò)
new Thread(futureTask).start()
運(yùn)行,F(xiàn)utureTask的get方法可以獲取Callable接口方法call方法的返回值 - 如果Callable接口方法call方法異常,在FutureTask的get方法調(diào)用時(shí)也會(huì)拋出同樣的異常
第四種:線程池 + execute
從JDK5版本開(kāi)始,java默認(rèn)提供了線程池的支持,用線程池的方式運(yùn)行線程可以避免線程的無(wú)限擴(kuò)張導(dǎo)致應(yīng)用宕機(jī),同時(shí)也節(jié)省了線程頻繁創(chuàng)建與銷毀的資源與時(shí)間成本。
public class FourthWay implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + ":實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池"); } public static void main(String[] args) { //創(chuàng)建一個(gè)固定大小的線程池 ExecutorService threadPool = Executors.newFixedThreadPool(5); for(int i = 0;i < 10;i++){ threadPool.execute(new FourthWay()); } } }
線程池ExecutorService使用execute方法運(yùn)行Runnable接口run方法的線程實(shí)現(xiàn),execute方法與run方法的共同特點(diǎn)是沒(méi)有返回值。
pool-1-thread-5:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池 pool-1-thread-2:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池 pool-1-thread-4:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池 pool-1-thread-4:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池 pool-1-thread-4:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池 pool-1-thread-1:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池 pool-1-thread-4:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池 pool-1-thread-3:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池 pool-1-thread-2:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池 pool-1-thread-5:實(shí)現(xiàn)線程的方式Runnable接口,但運(yùn)行方式不一樣,使用線程池
從上面的結(jié)果中可以看出,線程池中包含五個(gè)線程。線程運(yùn)行完成之后并不銷毀,而是還回到線程池,下一次執(zhí)行時(shí)從線程池中獲取線程資源再次運(yùn)行。
第五種:線程池 + submit
下面的例子線程池ExecutorService使用submit方法運(yùn)行Callable接口call方法的線程實(shí)現(xiàn),submit方法與call方法的共同特點(diǎn)是存在返回值。
- Callable接口call方法的返回值可以由泛型定義
- ExecutorService線程池submit方法的返回值是Future
Future的get方法可以獲取call方法的返回值,同時(shí)如果call方法拋出異常,F(xiàn)uture的get方法也會(huì)拋出異常。
public class FifthWay implements Callable<String> { @Override public String call() throws Exception { return Thread.currentThread().getName() + ":Callable接口帶返回值,可以拋出異常"; } //模擬測(cè)試 public static void main(String[] args) throws ExecutionException, InterruptedException { //保存多線程執(zhí)行結(jié)果 List<String> retList = new ArrayList<>(); //創(chuàng)建一個(gè)固定大小的線程池 ExecutorService threadPool = Executors.newFixedThreadPool(5); for(int i = 0;i < 10;i++){ Future<String> future = threadPool.submit(new FifthWay()); retList.add(future.get()); } //java8 語(yǔ)法,打印retlist retList.forEach(System.out::println); } }
上文代碼中有一個(gè)小小的語(yǔ)法糖,retList.forEach(System.out::println);
是java8提供的方法引用
pool-1-thread-1:Callable接口帶返回值,可以拋出異常 pool-1-thread-2:Callable接口帶返回值,可以拋出異常 pool-1-thread-3:Callable接口帶返回值,可以拋出異常 pool-1-thread-4:Callable接口帶返回值,可以拋出異常 pool-1-thread-5:Callable接口帶返回值,可以拋出異常 pool-1-thread-1:Callable接口帶返回值,可以拋出異常 pool-1-thread-2:Callable接口帶返回值,可以拋出異常 pool-1-thread-3:Callable接口帶返回值,可以拋出異常 pool-1-thread-4:Callable接口帶返回值,可以拋出異常 pool-1-thread-5:Callable接口帶返回值,可以拋出異常
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Java中雙重檢查鎖(double checked locking)的正確實(shí)現(xiàn)
雙重檢查鎖(Double-Check Locking),顧名思義,通過(guò)兩次檢查,并基于加鎖機(jī)制,實(shí)現(xiàn)某個(gè)功能,下面這篇文章主要給大家介紹了關(guān)于Java中雙重檢查鎖(double checked locking)的相關(guān)資料,需要的朋友可以參考下2021-09-09解決idea報(bào)錯(cuò) Connot resolve column 的問(wèn)題
這篇文章主要介紹了解決idea報(bào)錯(cuò) Connot resolve column 的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02springboot 注冊(cè)服務(wù)注冊(cè)中心(zk)的兩種方式詳解
本文通過(guò)一個(gè)demo講述一下這兩種注冊(cè)方式,使用的是傳統(tǒng)的向zk注冊(cè)的方案。對(duì)springboot 注冊(cè)zk的相關(guān)知識(shí)感興趣的朋友一起看看吧2018-01-01Java 生產(chǎn)者/消費(fèi)者問(wèn)題實(shí)例詳解
這篇文章主要實(shí)例分析了java中生產(chǎn)者消費(fèi)者問(wèn)題的方法,需要的朋友可以可以參考下2017-04-04Spring?Boot實(shí)現(xiàn)消息的發(fā)送和接收使用實(shí)戰(zhàn)指南
這篇文章主要為大家介紹了Spring?Boot實(shí)現(xiàn)消息的發(fā)送和接收使用實(shí)戰(zhàn)指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06解決cmd運(yùn)行java程序“找不到文件”提示的方案
在本篇文章里小編給大家分享的是關(guān)于解決cmd運(yùn)行java程序“找不到文件”提示的方案,有需要的朋友們可以參考下。2020-02-02SpringBoot 過(guò)濾器與攔截器實(shí)例演示
本文通過(guò)示例代碼給大家講解SpringBoot 過(guò)濾器與攔截器的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-11-11