国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

聊一聊三種基本方法創(chuàng)建線程

開發(fā) 前端
挺基礎(chǔ)的知識(shí),一開始不是很愿意寫,畢竟這種簡(jiǎn)單的知識(shí)大家不一定愿意看,而且容易寫的大眾化,不過還好梳理一遍下來還算是有點(diǎn)收獲,比如我看了 Thread 類重寫的 run 方法,才明白為什么可以把任務(wù)(Runnable)和線程本身(Thread)分開來。

 [[399145]]

本文轉(zhuǎn)載自微信公眾號(hào)「飛天小牛肉」,作者飛天小牛肉。轉(zhuǎn)載本文請(qǐng)聯(lián)系飛天小牛肉公眾號(hào)。

挺基礎(chǔ)的知識(shí),一開始不是很愿意寫,畢竟這種簡(jiǎn)單的知識(shí)大家不一定愿意看,而且容易寫的大眾化,不過還好梳理一遍下來還算是有點(diǎn)收獲,比如我看了 Thread 類重寫的 run 方法,才明白為什么可以把任務(wù)(Runnable)和線程本身(Thread)分開來。

創(chuàng)建線程的三種方法

線程英譯是 Thread,這也是 Java 中線程對(duì)應(yīng)的類名,在 java.lang 包下。

注意下它實(shí)現(xiàn)了 Runnable 接口,下文會(huì)詳細(xì)解釋。

線程與任務(wù)合并 — 直接繼承 Thread 類

線程創(chuàng)建出來自然是需要執(zhí)行一些特定的任務(wù)的,一個(gè)線程需要執(zhí)行的任務(wù)、或者說需要做的事情就在 Thread 類的 run 方法里面定義。

這個(gè) run 方法是哪里來的呢?

事實(shí)上,它并不是 Thread 類自己的。Thread 實(shí)現(xiàn)了 Runnable 接口,run 方法正是在這個(gè)接口中被定義為了抽象方法,而 Thread 實(shí)現(xiàn)了這個(gè)方法。

所以,我們把這個(gè) Runnable 接口稱為任務(wù)類可能更好理解。

如下,就是通過集成 Thread 類創(chuàng)建一個(gè)自定義線程 Thread1 的示例:

  1. // 自定義線程對(duì)象 
  2. class Thread1 extends Thread { 
  3.     @Override 
  4.  public void run() { 
  5.   // 線程需要執(zhí)行的任務(wù) 
  6.   ...... 
  7.    } 
  8.  
  9. // 創(chuàng)建線程對(duì)象 
  10. Thread1 t1 = new Thread1(); 

看這里,Thread 類提供了一個(gè)構(gòu)造函數(shù),可以為某個(gè)線程指定名字:

所以,我們可以這樣:

  1. // 創(chuàng)建線程對(duì)象 
  2. Thread1 t1 = new Thread1("t1"); 

這樣,控制臺(tái)打印的時(shí)候就比較明了,一眼就能知道是哪個(gè)線程輸出的。

當(dāng)然了,一般來說,我們寫的代碼都是下面這種匿名內(nèi)部類簡(jiǎn)化版本的:

  1. // 創(chuàng)建線程對(duì)象 
  2. Thread t1 = new Thread("t1") { 
  3.  @Override 
  4.  // run 方法內(nèi)實(shí)現(xiàn)了要執(zhí)行的任務(wù) 
  5.  public void run() { 
  6.   // 線程需要執(zhí)行的任務(wù) 
  7.      ...... 
  8.   } 
  9. }; 

線程與任務(wù)分離 — Thread + 實(shí)現(xiàn) Runnable 接口

假如有多個(gè)線程,這些線程執(zhí)行的任務(wù)都是一樣的,那按照上述方法一的話我們豈不是就得寫很多重復(fù)代碼?

所以,我們考慮把線程執(zhí)行的任務(wù)與線程本身分離開來。

  1. class MyRunnable implements Runnable { 
  2.     @Override 
  3.     public void run() { 
  4.         // 線程需要執(zhí)行的任務(wù) 
  5.      ...... 
  6.     } 
  7.  
  8. // 創(chuàng)建任務(wù)類對(duì)象 
  9. MyRunnable runnable = new MyRunnable(); 
  10. // 創(chuàng)建線程對(duì)象 
  11. Thread t2 = new Thread(runnable); 

除了避免了重復(fù)代碼,使用實(shí)現(xiàn) Runnable 接口的方式也比方法一的單繼承 Thread 類更具靈活性,畢竟一個(gè)類只能繼承一個(gè)父類,如果這個(gè)類本身已經(jīng)繼承了其它類,就不能使用第一種方法了。另外,用這種方式,也更容易與線程池等高級(jí) API 相結(jié)合。

因此,一般來說,更推薦使用這種方式去創(chuàng)建線程。也就是說,不推薦直接操作線程對(duì)象,推薦操作任務(wù)對(duì)象。

上述代碼使用匿名內(nèi)部類的簡(jiǎn)化版本如下:

  1. // 創(chuàng)建任務(wù)類對(duì)象 
  2. Runnable runnable = new Runnable() { 
  3.     public void run(){ 
  4.         // 要執(zhí)行的任務(wù) 
  5.         ...... 
  6.     } 
  7. }; 
  8.  
  9. // 創(chuàng)建線程對(duì)象 
  10. Thread t2 = new Thread(runnable); 

同樣的,我們也可以為其指定線程名字:

  1. Thread t2 = new Thread(runnable, "t2"); 

以上兩個(gè) Thread 的構(gòu)造函數(shù)如圖所示:

可以發(fā)現(xiàn),Thread 類的構(gòu)造函數(shù)無一例外全部調(diào)用了 init 方法,這個(gè)方法到底做了啥?我們點(diǎn)進(jìn)去看看:

它將構(gòu)造函數(shù)傳進(jìn)來的 Runnable 對(duì)象傳給了一個(gè)成員變量 target。

target 就是 Thread 類中定義的 Runnable 對(duì)象,代表著需要執(zhí)行的任務(wù)(What will be run)。

這個(gè)變量的存在,就是我們能夠把任務(wù)(Runnable)和線程本身(Thread)分開的原因所在。看下面這段代碼:

沒錯(cuò),這就是 Thread 類默認(rèn)實(shí)現(xiàn)的 run 方法。

在使用第一種方法創(chuàng)建線程的時(shí)候,我們定義了一個(gè) Thread 子類并重寫了其父類的 run 方法,所以這個(gè)父類實(shí)現(xiàn)的 run 方法不會(huì)被執(zhí)行,執(zhí)行的是我們自定義的子類中的 run 方法。

而在使用第二種方法創(chuàng)建線程的時(shí)候,我們并沒有在 Thread 子類中重寫 run 方法,所以父類默認(rèn)實(shí)現(xiàn)的 run 方法就會(huì)被執(zhí)行。

而這段 run 方法代碼的意思就是說,如果 taget != null,也就是說如果 Thread 構(gòu)造函數(shù)中傳入了 Runnable 對(duì)象,那就執(zhí)行這個(gè) Runnable 對(duì)象的 run 方法。

線程與任務(wù)分離 — Thread + 實(shí)現(xiàn) Callable 接口

雖然 Runnable 挺不錯(cuò)的,但是仍然有個(gè)缺點(diǎn),那就是沒辦法獲取任務(wù)的執(zhí)行結(jié)果,因?yàn)樗?run 方法返回值是 void。

這樣,對(duì)于需要獲取任務(wù)執(zhí)行結(jié)果的線程來說,Callable 就成為了一個(gè)完美的選擇。

Callable 和 Runnable 基本差不多:

和 Runnbale 比起來,Callable 不過就是把 run 改成了 call。當(dāng)然,最重要的是!和 void run 不同,這個(gè) call 方法是擁有返回值的,而且能夠拋出異常。

這樣,一個(gè)很自然的想法,就是把 Callable 作為任務(wù)對(duì)象傳給 Thread,然后 Thread 重寫 call 方法就完事兒。

But,遺憾的是,Thread 類的構(gòu)造函數(shù)里并不接收 Callable 類型的參數(shù)。

所以,我們需要把 Callable 包裝一下,包裝成 Runnable 類型,這樣就能傳給 Thread 構(gòu)造函數(shù)了。

為此,F(xiàn)utureTask 成為了最好的選擇。

可以看到 FutureTask 間接繼承了 Runnable 接口,因此它也可以看作是一個(gè) Runnable 對(duì)象,可以作為參數(shù)傳入 Thread 類的構(gòu)造函數(shù)。

另外,F(xiàn)utureTask 還間接繼承了 Future 接口,并且,這個(gè) Future 接口定義了可以獲取 call() 返回值的方法 get:

看下面這段代碼,使用 Callable 定義一個(gè)任務(wù)對(duì)象,然后把 Callable 包裝成 FutureTask,然后把 FutureTask 傳給 Thread 構(gòu)造函數(shù),從而創(chuàng)建出一個(gè)線程對(duì)象。

另外,Callable 和 FutureTask 的泛型填的就是 Callable 任務(wù)返回的結(jié)果類型(就是 call 方法的返回類型)。

  1. class MyCallable implements Callable<Integer> { 
  2.     @Override 
  3.     public Integer call() throws Exception { 
  4.         // 要執(zhí)行的任務(wù) 
  5.         ...... 
  6.         return 100; 
  7.     } 
  8. // 將 Callable 包裝成 FutureTask,F(xiàn)utureTask也是一種Runnable 
  9. MyCallable callable = new MyCallable(); 
  10. FutureTask<Integer> task = new FutureTask<>(callable); 
  11. // 創(chuàng)建線程對(duì)象 
  12. Thread t3 = new Thread(task); 

當(dāng)線程運(yùn)行起來后,可以通過 FutureTask 的 get 方法獲取任務(wù)運(yùn)行結(jié)果:

  1. Integer result = task.get(); 

不過,需要注意的是,get 方法會(huì)阻塞住當(dāng)前調(diào)用這個(gè)方法的線程。比如說我們?cè)谥骶€程中調(diào)用了 get 方法去獲取 t3 線程的任務(wù)運(yùn)行結(jié)果,那么只有這個(gè) call 方法成功返回了,主線程才能夠繼續(xù)往下執(zhí)行。

換句話說,如果 call 方法一直得不到結(jié)果,那么主線程也就一直無法向下運(yùn)行。

啟動(dòng)線程

OK,綜上,我們已經(jīng)把線程成功創(chuàng)建出來了,那么怎么把它啟動(dòng)起來呢?

以第一種創(chuàng)建線程的方法為例:

  1. // 創(chuàng)建線程 
  2. Thread t1 = new Thread("t1") { 
  3.  @Override 
  4.  // run 方法內(nèi)實(shí)現(xiàn)了要執(zhí)行的任務(wù) 
  5.  public void run() { 
  6.   // 線程需要執(zhí)行的任務(wù) 
  7.      ...... 
  8.   } 
  9. }; 
  10.  
  11. // 啟動(dòng)線程 
  12. t1.start(); 

這里涉及一道經(jīng)典的面試題,即為什么使用 start 啟動(dòng)線程,而不使用 run 方法啟動(dòng)線程?

使用 run 方法啟動(dòng)線程看起來好像并沒啥問題,對(duì)吧,run 方法內(nèi)定義了要執(zhí)行的任務(wù),調(diào)用 run 方法不就執(zhí)行了這個(gè)任務(wù)了?

這確實(shí)沒錯(cuò),任務(wù)確實(shí)能夠被正確執(zhí)行,但是并不是以多線程的方式,當(dāng)我們使用 t1.run() 的時(shí)候,程序仍然是在創(chuàng)建 t1 線程的 main 線程下運(yùn)行的,并沒有創(chuàng)建出一個(gè)新的 t1 線程。

舉個(gè)例子:

  1. // 創(chuàng)建線程 
  2. Thread t1 = new Thread("t1") { 
  3.     @Override 
  4.     public void run() { 
  5.       // 線程需要執(zhí)行的任務(wù) 
  6.       System.out.println("開始執(zhí)行"); 
  7.       FileReader.read(文件地址); // 讀文件 
  8.     } 
  9. }; 
  10.  
  11. t1.run(); 
  12. System.out.println("執(zhí)行完畢"); 

如果使用 run 方法啟動(dòng)線程,"執(zhí)行完畢" 這句話需要在文件讀取完畢后才能夠輸出,也就是說讀文件這個(gè)操作仍然是同步的。假設(shè)讀取操作花費(fèi)了 5 秒鐘,如果沒有線程調(diào)度機(jī)制,這 5 秒 CPU 什么都做不了,其它代碼都得暫停。

而如果使用 start 方法啟動(dòng)線程,"執(zhí)行完畢" 這句話在文件讀取完畢之前就會(huì)被很快地輸出,因?yàn)槎嗑€程讓方法執(zhí)行變成了異步的,讀取文件這個(gè)操作是 t1 線程在做,而 main 線程并沒有被阻塞。

 

責(zé)任編輯:武曉燕 來源: 飛天小牛肉
相關(guān)推薦

2022-09-26 08:03:25

VMware虛擬機(jī)

2023-03-31 09:29:18

代碼量統(tǒng)計(jì)代碼增刪

2025-01-10 08:15:22

C#異步底層

2023-05-15 08:38:58

模板方法模式

2021-02-22 14:04:47

Vue框架項(xiàng)目

2023-11-04 16:28:54

2023-07-25 15:06:39

2022-06-01 09:51:51

Golang方法接收者

2018-06-07 13:17:12

契約測(cè)試單元測(cè)試API測(cè)試

2020-09-15 12:45:48

系統(tǒng)LinuxUnix

2023-02-09 10:39:15

gRPC通信模式

2024-09-09 08:29:25

2021-09-09 08:55:49

節(jié)點(diǎn)累加樹二叉

2021-03-29 00:02:10

C#Attribute元素

2023-09-22 17:36:37

2020-05-22 08:16:07

PONGPONXG-PON

2021-01-28 22:31:33

分組密碼算法

2022-09-19 16:24:33

數(shù)據(jù)可視化Matplotlib工具

2020-08-12 08:34:16

開發(fā)安全We

2022-10-08 11:33:56

邊緣計(jì)算云計(jì)算
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

欧美艳星kaydenkross| 美日韩精品视频| 欧美日韩日日摸| 久久国产精品视频在线观看| 奇米色欧美一区二区三区| 日韩精品一区在线观看| 白天操夜夜操| 国产v日产∨综合v精品视频| 成人h视频在线观看播放| 日本不卡一二三| 91福利国产精品| 熟女少妇精品一区二区| 久久一区中文字幕| 国产精品av在线| 国产成人精品一区二区三区在线| 欧美影视一区二区三区| 国产免费999| 国产原创一区二区| 成人18视频| 色婷婷综合久久久久久| 亚洲人成电影在线| 欧美三级理伦电影| 亚洲午夜私人影院| 黄在线观看网站| 久久电影网站中文字幕| 波多野结衣一区二区三区在线观看| 99久久香蕉| 色婷婷成人综合| 丁香花电影在线观看完整版| 疯狂欧美牲乱大交777| 日韩在线第三页| 国产成人高清在线| 亚洲精品二区| 欧美专区一区二区三区| 成人久久久久爱| 美女久久久久| 久久久久久亚洲精品不卡| 一区二区三区短视频| 91麻豆精品国产91久久久资源速度| 久草在线免费福利| 一区二区三区高清在线| 成人午夜剧场免费观看完整版| 丁香六月综合激情| 精品少妇人妻av一区二区| 噜噜噜躁狠狠躁狠狠精品视频 | 国产一区二区三区丝袜| 伊人在我在线看导航| 3atv一区二区三区| 国产精品一区二区免费| 亚洲成人最新网站| 欧美疯狂做受xxxx富婆| 婷婷视频在线播放| 欧美欧美在线| 精品在线免费视频| 欧美高清一级大片| 日韩不卡手机在线v区| 国产成人精品最新| 欧美日韩色图| 海角社区69精品视频| 亚洲欧美日韩综合国产aⅴ| 91精品免费久久久久久久久| 亚洲字幕久久| 亚洲va久久| www.欧美精品| 精品人人人人| 亚洲综合日韩欧美| 97久久精品人人澡人人爽| 久久99久久99精品中文字幕| 国产精品久久久久9999爆乳| 91九色在线播放| 欧美1区免费| 欧美一级欧美三级在线观看| 免费电影网站在线视频观看福利| 亚洲人成电影在线观看天堂色| 欧美天堂在线| 日韩av大片免费看| 激情综合中文娱乐网| 亚洲综合第一| 欧美激情自拍偷拍| 欧美捆绑视频| 亚洲欧美日韩中文在线制服| 久久中文资源| 久久精品中文字幕一区二区三区 | 亚洲精品男人| 日韩女同互慰一区二区| 欧美爱爱视频| 成人欧美一区二区三区在线湿哒哒 | 超碰在线资源| 久久精品夜夜夜夜夜久久| 亚洲尤物av| 国产一区二区三区四区五区在线| 国产美女久久久久| 日本视频一二区| 日韩午夜在线观看视频| 91欧美日韩在线| 久久久久久久久久久久久9999| aaa国产一区| 国产精品四虎| 欧美大片在线看免费观看| 亚洲日韩视频| 午夜电影福利网| 日韩av在线天堂网| 人人狠狠综合久久亚洲婷| 视频一区二区视频| 日韩欧美国产中文字幕| 亚洲精品三区| 久久综合狠狠综合久久综青草 | 国产99在线播放| 97se亚洲国产综合在线| 黄色av免费在线看| 欧美激情高清视频| 日本午夜精品视频在线观看| 导航艳情国产电影| 亚洲人在线观看| 欧美在线网址| 日韩欧美国产片| 亚洲国产欧美一区| 欧美久久99| 先锋在线亚洲| 中文字幕欧美专区| 日韩av一二三| av国产在线观看| 国产成人在线一区二区| 成人午夜视频在线观看| 国产精品刘玥久久一区| 国产欧美精品在线播放| 亚洲国产精品激情在线观看| 周于希免费高清在线观看| 精品一区2区三区| 精品成人久久av| 窝窝社区一区二区| 免费观看成人网| 色婷婷**av毛片一区| 韩国三级中文字幕hd久久精品| 在线观看麻豆| 99在线观看视频| 亚洲图片欧美一区| 免费一区二区三区视频导航| av无码精品一区二区三区| 一区二区三区久久精品| 久久国产精品无码网站| a级影片在线观看| 精品免费国产| 欧美日韩高清影院| 亚洲精品九九| 日本中文字幕电影在线免费观看| 国产精品视频一区二区高潮| 亚洲视频免费在线| 成人爽a毛片免费啪啪红桃视频| www.中文字幕在线| 精品激情国产视频| 91丨porny丨户外露出| 日韩欧美激情| 日本成人在线免费视频| 免费成人高清视频| 久久精品一区二区三区四区| 香蕉成人app| 三年中国国语在线播放免费| 欧美黑人国产人伦爽爽爽| 国产色产综合色产在线视频| 天堂va在线高清一区| 欧美日韩怡红院| 91高清在线免费观看| 亚洲人精品一区| 色婷婷亚洲mv天堂mv在影片| 国产91久久久久蜜臀青青天草二 | 男人的天堂亚洲在线| 老司机在线视频二区| 国产伦精品一区二区三区免 | 超碰影院在线观看| 欧美极品少妇xxxxx| 一区精品在线播放| 欧美天天综合| 九色在线观看视频| 日本一区高清不卡| 亚洲欧美国产另类| 99久久99久久久精品齐齐| 国产亚洲久久| 免费黄色av电影| 91精品国产91久久久久青草| 欧美精品成人一区二区三区四区| 久久爱另类一区二区小说| 日韩综合av| 性综艺节目av在线播放| 99精品国产高清一区二区| 日韩一级完整毛片| 91丨九色丨尤物| 欧洲福利电影| 国产激情在线| 亚洲国产精品久久久久爰色欲| 日韩美女av在线免费观看| 欧美亚洲禁片免费| 粉嫩aⅴ一区二区三区四区五区 | 美女av免费在线观看| 26uuu国产精品视频| 91黄色激情网站| 国产黑丝在线一区二区三区| 亚洲综合福利| 在线中文字幕-区二区三区四区| 妺妺窝人体色777777|