<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官問我:創(chuàng)建線程有幾種方式?我笑了

          共 3896字,需瀏覽 8分鐘

           ·

          2020-11-13 09:40

          前言

          多線程在面試中基本上已經(jīng)是必問項(xiàng)了,面試官通常會從簡單的問題開始發(fā)問,然后再一步一步的挖掘你的知識面。

          比如,從線程是什么開始,線程和進(jìn)程的區(qū)別,創(chuàng)建線程有幾種方式,線程有幾種狀態(tài),等等。

          接下來自然就會引出線程池,Lock,Synchronized,JUC的各種并發(fā)包。然后就會引出 AQS、CAS、JMM、JVM等偏底層原理,一環(huán)扣一環(huán)。

          這一節(jié)我們不聊其他的,只說創(chuàng)建線程有幾種方式。

          是不是感覺非常簡單,不就是那個啥啥那幾種么。

          其實(shí)不然,只有我們給面試官解釋清楚了,并加上我們自己的理解,才能在面試中加分。

          正文

          一般來說我們比較常用的有以下四種方式,下面先介紹它們的使用方法。然后,再說面試中怎樣回答面試官的問題比較合適。

          1、繼承 Thread 類

          通過繼承 Thread 類,并重寫它的 run 方法,我們就可以創(chuàng)建一個線程。

          • 首先定義一個類來繼承 Thread 類,重寫 run 方法。
          • 然后創(chuàng)建這個子類對象,并調(diào)用 start 方法啟動線程。

          2、實(shí)現(xiàn) Runnable 接口

          通過實(shí)現(xiàn) Runnable ,并實(shí)現(xiàn) run 方法,也可以創(chuàng)建一個線程。

          • 首先定義一個類實(shí)現(xiàn) Runnable 接口,并實(shí)現(xiàn) run 方法。
          • 然后創(chuàng)建 Runnable 實(shí)現(xiàn)類對象,并把它作為 target 傳入 Thread 的構(gòu)造函數(shù)中
          • 最后調(diào)用 start 方法啟動線程。

          3、實(shí)現(xiàn) Callable 接口,并結(jié)合 Future 實(shí)現(xiàn)

          • 首先定義一個 Callable 的實(shí)現(xiàn)類,并實(shí)現(xiàn) call 方法。call 方法是帶返回值的。
          • 然后通過 FutureTask 的構(gòu)造方法,把這個 Callable 實(shí)現(xiàn)類傳進(jìn)去。
          • 把 FutureTask 作為 Thread 類的 target ,創(chuàng)建 Thread 線程對象。
          • 通過 FutureTask 的 get 方法獲取線程的執(zhí)行結(jié)果。

          4、通過線程池創(chuàng)建線程

          此處用 JDK 自帶的 Executors 來創(chuàng)建線程池對象。

          • 首先,定一個 Runnable 的實(shí)現(xiàn)類,重寫 run 方法。
          • 然后創(chuàng)建一個擁有固定線程數(shù)的線程池。
          • 最后通過 ExecutorService 對象的 execute 方法傳入線程對象。

          到底有幾種創(chuàng)建線程的方式?

          那么問題來了,我這里舉例了四種創(chuàng)建線程的方式,是不是說明就是四種呢?

          我們先看下 JDK 源碼中對 Thread 類的一段解釋,如下圖。

          There are two ways to create a new thread of execution

          翻譯:有兩種方式可以創(chuàng)建一個新的執(zhí)行線程

          這里說的兩種方式就對應(yīng)我們介紹的前兩種方式。

          但是,我們會發(fā)現(xiàn)這兩種方式,最終都會調(diào)用 Thread.start 方法,而 start 方法最終會調(diào)用 run 方法。

          不同的是,在實(shí)現(xiàn) Runnable 接口的方式中,調(diào)用的是 Thread 本類的 run 方法。我們看下它的源碼,

          這種方式,會把創(chuàng)建的 Runnable 實(shí)現(xiàn)類對象賦值給 target ,并運(yùn)行 target 的 run 方法。

          再看繼承 Thread 類的方式,我們同樣需要調(diào)用 Thread 的 start 方法來啟動線程。由于子類重寫了 Thread 類的 run 方法,因此最終執(zhí)行的是這個子類的 run 方法。

          所以,我們也可以這樣說。在本質(zhì)上,創(chuàng)建線程只有一種方式,就是構(gòu)造一個 Thread 類(其子類其實(shí)也可以認(rèn)為是一個 Thread 類)。

          而構(gòu)造 Thread 類又有兩種方式,一種是繼承 Thread 類,一種是實(shí)現(xiàn) Runnable接口。其最終都會創(chuàng)建 Thread 類(或其子類)的對象。

          再來看實(shí)現(xiàn) Callable ,結(jié)合 Future 和 FutureTask 的方式??梢园l(fā)現(xiàn),其最終也是通過 ?new Thread(task) 的方式構(gòu)造 Thread 類。

          最后,在線程池中,我們其實(shí)是把創(chuàng)建和管理線程的任務(wù)都交給了線程池。而創(chuàng)建線程是通過線程工廠類 DefaultThreadFactory 來創(chuàng)建的(也可以自定義工廠類)。我們看下這個工廠類的具體實(shí)現(xiàn)。

          它會給線程設(shè)置一些默認(rèn)值,如線程名稱,線程的優(yōu)先級,線程組,是否是守護(hù)線程等。最后還是通過 new Thread() 的方式來創(chuàng)建線程的。

          因此,綜上所述。在回答這個問題的時候,我們可以說本質(zhì)上創(chuàng)建線程就只有一種方式,就是構(gòu)造一個 Thread 類。(此結(jié)論借鑒來源于 Java 并發(fā)編程 78 講 -- 徐隆曦)

          個人想法

          但是,在這里我想對這個結(jié)論稍微提出一些疑問(若有不同見解,文末可留言交流~)。。。

          個人認(rèn)為,如果你要說有 1種、2種、3種、4種 其實(shí)也是可以的。重要的是,你要能說出你的依據(jù),講出它們各自的不同點(diǎn)和共同點(diǎn)。講得頭頭是道,讓面試官對你頻頻點(diǎn)頭。。

          說只有構(gòu)造 Thread 類這一種創(chuàng)建線程方式,個人認(rèn)為還是有些牽強(qiáng)。因?yàn)?,無論你從任何手段出發(fā),想創(chuàng)建一個線程的話,最終肯定都是構(gòu)造 Thread 類。(包括以上幾種方式,甚至通過反射,最終不也是 newInstance 么)。

          那么,如果按照這個邏輯的話,我就可以說,不管創(chuàng)建任何的對象(Object),都是只有一種方式,即構(gòu)造這個對象(Object) 類。這個結(jié)論似乎有些太過無聊了,因?yàn)檫@是一句非常正確的廢話。

          以 ArrayList 為例,我問你創(chuàng)建 ArrayList 有幾種方式。你八成會為了炫耀自己知道的多,跟我說,

          1. 通過構(gòu)造方法,List list = new ArrayList();
          2. 通過 Arrays.asList("a", "b");
          3. 通過Java8提供的Stream API,如 List list = Stream.of("a", "b").collect(Collectors.toList());
          4. 通過guava第三方j(luò)ar包,List list3 = Lists.newArrayList("a", "b");

          等等,僅以上就列舉了四種?,F(xiàn)在,我告訴你創(chuàng)建 ArrayList 就只有一種方式,即構(gòu)造一個 ArrayList 類,你抓狂不。

          這就如同,我問你從北京出發(fā)到上海去有幾種方式。

          你說可以坐汽車、火車、坐動車、坐高鐵,坐飛機(jī)。

          那不對啊,動車和高鐵都屬于火車啊,汽車和火車都屬于車,車和飛機(jī)都屬于交通工具。這樣就是只有一種方式了,即坐交通工具。

          這也不對啊,我不坐交通工具也行啊,我走路過去不行么(我插眼傳送也可以啊,就你皮~)。

          最后結(jié)論就是,只有一種方式,那就是你人到上海即可。這這這,這算什么結(jié)論。。。

          所以個人認(rèn)為,說創(chuàng)建線程只有一種方式有些欠妥。

          好好的一個技術(shù)文,差一點(diǎn)被我寫成議論文了。。。

          這個仁者見仁智者見智吧。

          最后,我們看一下我從網(wǎng)上看到的一個非常有意思的題目。

          有趣的題目

          問:一個類實(shí)現(xiàn)了 Runnable 接口就會執(zhí)行默認(rèn)的 run 方法,然后判斷 target 不為空,最后執(zhí)行在 Runnable接口中實(shí)現(xiàn)的 run 方法。而繼承 Thread 類,就會執(zhí)行重寫后的 run 方法。那么,現(xiàn)在我既繼承 Thread 類,又實(shí)現(xiàn) Runnable 接口,如下程序,應(yīng)該輸出什么結(jié)果呢?

          public?class?TestThread?{
          ????public?static?void?main(String[]?args)?{
          ????????new?Thread(()->?System.out.println("runnable")){
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("Thread?run");
          ????????????}
          ????????}.start();
          ????}
          }

          可能乍一看很懵逼,這是什么操作。

          其實(shí),我們拆解一下以上代碼就會知道,這是一個繼承了 Thread 父類的子類對象,重寫了父類的 run 方法。然后,父對象 Thread 中,在構(gòu)造方法中傳入了一個 Runnable 接口的實(shí)現(xiàn)類,實(shí)現(xiàn)了 run 方法。

          現(xiàn)在執(zhí)行了 start 方法,必然會先在子類中尋找 run 方法,找到了就會直接執(zhí)行,不會執(zhí)行父類的 run 方法了,因此結(jié)果為:Thread run 。

          若假設(shè)子類沒有實(shí)現(xiàn) run 方法,那么就會去父類中尋找 run 方法,而父類的 run 方法會判斷是否有 Runnable傳過來(即判斷target是否為空),現(xiàn)在 target 不為空,因此就會執(zhí)行 target.run 方法,即打印結(jié)果:runnable。

          所以,上邊的代碼看起來復(fù)雜,實(shí)則很簡單。透過現(xiàn)象看本質(zhì),我們就會發(fā)現(xiàn),它不過就是考察類的父子繼承關(guān)系,子類重寫了父類的方法就會優(yōu)先執(zhí)行子類重寫的方法。

          和線程結(jié)合起來,如果對線程運(yùn)行機(jī)制不熟悉的,很可能就會被迷惑。




          推薦閱讀:


          喜歡我可以給我設(shè)為星標(biāo)哦

          好文章,我“在看”
          瀏覽 42
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品www | 国产精品www...xxc | 在线啪| 日韩AV电影网站 | 成 人 免费 黄 色 |