最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

每日六道java新手入門面試題,通往自由的道路--多線程

 更新時間:2021年07月01日 09:45:12   作者:太子爺哪吒  
這篇文章主要為大家分享了最有價值的6道多線程面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,對hashCode方法的設(shè)計、垃圾收集的堆和代進行剖析,感興趣的小伙伴們可以參考一下

1. 你可以講下進程與線程的區(qū)別?為什么要用多線程?

  • 進程:進程是程序的一次執(zhí)行過程,是系統(tǒng)運行程序的基本單位。
  • 線程:單個進程中執(zhí)行中每個任務(wù)就是一個線程。線程是進程中執(zhí)行運算的最小單位。
  • 區(qū)別
    • 一個程序至少有一個進程,一個進程至少有一個線程。
    • 一個線程只能屬于一個進程,但是一個進程可以擁有多個線程。多線程處理就是允許一個進程中在同一時刻執(zhí)行多個任務(wù)即多個線程。
    • 每個獨立的進程有程序運行的入口、順序執(zhí)行序列和程序出口。但是線程不能獨立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個線程執(zhí)行控制,兩者均可并發(fā)執(zhí)行

為什么要用多線程:

  • 發(fā)揮多核CPU的優(yōu)勢,采用多線程的方式去同時完成幾件事情而不互相干擾。
  • 能夠有效的防止阻塞,多條線程同時運行,哪怕一條線程的代碼執(zhí)行讀取數(shù)據(jù)阻塞,也不會影響其它任務(wù)的執(zhí)行。
  • 提高程序的效率。

2. 什么是上下文切換?

上下文切換一般發(fā)生在多線程情況下,因為一個 CPU 核心在任意時刻只能被一個線程使用,為了讓這些線程都能得到有效執(zhí)行,CPU 采取的策略是為每個線程分配時間片并輪轉(zhuǎn)的形式。而在多核cpu下,多線程是并行工作的,如果線程數(shù)多,單個核又會并發(fā)的調(diào)度線程,運行時就會讓一個線程的時間片用完的時候就會重新處于就緒狀態(tài)讓給其他線程使用,這個過程就屬于上下文切換。

對于我們Java程序線程來說,一旦一個線程搶占到CPU資源的使用權(quán)后,另一個線程需要保存當前的一個狀態(tài),以便下次搶占成功后可以回到當前狀態(tài),JVM中有塊內(nèi)存地址叫程序計數(shù)器,用于記錄保存線程執(zhí)行到哪一行代碼,它是每個線程獨有的。執(zhí)行任務(wù)從保存到再次加載的過程就是上下文切換。

實際上,上下文切換也是對系統(tǒng)意味著來說會消耗大量的CPU時間,消耗大量資源。

以下幾種情況會發(fā)生上下文切換。

  • 線程的cpu時間片用完
  • 在發(fā)生垃圾回收的時候
  • 我們自己調(diào)用了 sleep、yield、wait、join、synchronized、lock 等方法

3. 說說你知道的幾種創(chuàng)建線程的方式

創(chuàng)建線程有以下方式:

繼承Thread類,重載它的run方法。

  • 在我們自己定義一個繼承于Thread類的子類,并重寫里面run方法,編寫相關(guān)邏輯代碼。
  • 在測試類中創(chuàng)建我剛自定義的線程子類對象
  • 調(diào)用子類實例的star方法來啟動線程,通過start方法去調(diào)用到run方法里面的邏輯。

實現(xiàn) Runnalbe接口,重載 Runnalbe接口中的run方法實現(xiàn) 。

  • 我們定義一個實現(xiàn)Runnable接口實現(xiàn)類,并重寫里面的run方法
  • 在測試類中創(chuàng)建一個我們剛定義的接口實現(xiàn)類的實例,以實例對象作為target創(chuàng)建Thead對象,而得到的Thread對象就是我們線程子類對象。
  • 最后調(diào)用線程對象的start方法

實現(xiàn)Callable接口方式,重寫Callable接口中的call方法,并且這個call方法可以有返回值。

  • 我們定義一個實現(xiàn)創(chuàng)建實現(xiàn)Callable接口實現(xiàn)類,并重寫里面的call方法,注意它是call方法,并且有返回值。
  • 在測試類中創(chuàng)建一個我們剛定義的接口實現(xiàn)類的實例,以實例對象為參數(shù)創(chuàng)建FutureTask對象,并把創(chuàng)建出來FutureTask對象作為參數(shù)去創(chuàng)建Thread對象,而得到的Thread對象就是我們線程子類對象。
  • 最好調(diào)用線程對象的start方法。

需要注意三者的區(qū)別:

  • Thread是繼承,而Runnalbe、Callable是實現(xiàn)。對于繼承來說,只能單繼承,而接口可以多實現(xiàn)。如果繼承了 Thread類就無法再繼承其他類了。
  • 三者都是最后采用Thread.start()去啟動線程,而不是調(diào)用run方法,或者call方法的。
  • Runnable接口 run 方法無返回值;Callable接口 call 方法有返回值。
  • Runnable 接口 run 方法只能拋出運行時異常,且無法捕獲處理;Callable 接口 call 方法允許拋出異常,可以獲取異常信息
  • 使用實現(xiàn) Runnable接口的方式創(chuàng)建的線程可以處理同一資源,而實現(xiàn)資源的共享,還可以繼承其他類。

4. 昨天你講到創(chuàng)建線程后使用start方法去調(diào)用線程,為什么run方法不行呢?有什么區(qū)別?

我們先來看看代碼吧。

public class ThreadDemo {

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        MyThread myThead2 = new MyThread();
//        myThread.start();
//        myThead2.start();
        myThread.run();
        myThead2.run();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 6; i++) {
            System.out.println(Thread.currentThread().getName() + " :" + i);
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

這里我們創(chuàng)建了MyThread繼承了Thread類,這種方法是一種可以創(chuàng)建線程的方式。接著我們在main方法中創(chuàng)建了兩個線程,都調(diào)用了start方法和run方法。讓我們先看看結(jié)果吧!

// 注釋掉兩個run方法 開啟start方法得到的結(jié)果
Thread-0 :0
Thread-1 :0
Thread-1 :1
Thread-0 :1
Thread-1 :2
Thread-0 :2
Thread-1 :3
Thread-0 :3
Thread-1 :4
Thread-0 :4
Thread-1 :5
Thread-0 :5

// 注釋掉兩個start方法 開啟run方法得到的結(jié)果
main :0
main :1
main :2
main :3
main :4
main :5
main :0
main :1
main :2
main :3
main :4
main :5

接下來我們講一下:

1.start方法的作用:

啟動線程,相當于開啟一個線程調(diào)用我們重寫的run方法里面的邏輯,此時相當于有兩個線程,一個main的主線程和開啟的子線程??梢钥吹轿覀兊拇a,相當于有三個線程,一個主線程、一個Thread-0線程和一個Thread-1線程。并且線程之間是沒有順序的,他們是搶占cpu的資源來回切換的。

2.run方法的作用:

執(zhí)行線程的運行時代碼,相當于我們只是單純的調(diào)用一個普通方法。然后通過主線程的順序調(diào)用的方式,從myThread調(diào)用run方法結(jié)束后到myThread2去調(diào)用run方法結(jié)束,并且我們也可以看到我們控制臺中的線程名字就是main主線程。

3.run方法我們可以重復調(diào)用,而start方法在一個線程中只能調(diào)用一次。即myThread這個實例對象只能調(diào)用一次start方法,如果再調(diào)用一次start方法的話,就會拋出IllegalThreadStateException 的異常。

4.我們調(diào)用start方法算是真正意義上的多線程,因為它是額外開啟一個子線程去調(diào)用我們的run方法了。如果我們是調(diào)用run方法,就需要等待上一次的run方法執(zhí)行完畢才能調(diào)用下一次。所以我們要調(diào)用start方法充分揮多核CPU的優(yōu)勢,采用多線程的方式去同時完成幾件事情而不互相干擾。

5. 你知道你開啟一個線程后,它的狀態(tài)有那些嗎?

我們可以通過查看Thread的源碼中State枚舉發(fā)現(xiàn)有6個狀態(tài):

    public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

接下來我們具體來說說吧:

NEW(新建)

線程剛被創(chuàng)建,還只是一個實例對象,并未調(diào)用start方法啟動。。MyThread myThread = new MyThread只有線程對象,沒有線程特征。

Runnable(可運行)

在創(chuàng)建對象對象完成后,調(diào)用了myThread.start()方法線程,可以在Java虛擬機中運行的狀態(tài),可能正在運行自己代碼,也可能沒有,這取決于操作系統(tǒng)處理器。也可以叫做處于就緒狀態(tài),需要等待被線程調(diào)度選中,獲取cpu資源的使用權(quán)。

Teminated(被終止)

因為run方法正常退出而死亡,或者因為沒有捕獲的異常終止了run方法而死亡。代表著此線程的生命周期結(jié)束了。

處于運行狀態(tài)中的線程由于某種原因,暫時放棄對 CPU的使用權(quán),停止執(zhí)行,此時進入阻塞狀態(tài),直到其進入到就緒狀態(tài),才 有機會再次被 CPU 調(diào)用以進入到運行狀態(tài)。有以下三種相關(guān)阻塞狀態(tài):

Blocked(鎖阻塞)

當一個線程試圖獲取一個對象鎖如(Synchronzied或Lock),而該對象鎖被其他的線程持有,則該線程進入Blocked狀態(tài);只有當該線程持有鎖時,該線程將變成Runnable狀態(tài)。

Waiting(無限等待)

在調(diào)用了wait方法,JVM會把該線程放入等待隊列中,等待另一個線程執(zhí)行一個(喚醒),該線程此時狀態(tài)表示進入Waiting狀態(tài)。進入這個狀態(tài)后是不能自動喚醒的,必須等待另一個線程調(diào)用notify或者notifyAll方法才能夠喚醒。

TimedWaiting(計時等待)

同waiting狀態(tài)一樣,調(diào)用sleep方法或者其他超時方法時,他們將進入Timed Waiting狀態(tài)。不過這一狀態(tài)只需保持到超時期滿或者接收到喚醒通知。

6. 既然講到超時方法,那你講下sleep和wait的區(qū)別和他們需要怎樣喚醒

sleep和wait方法他們都是可以暫停當前線程的執(zhí)行,進入一個阻塞狀態(tài)。

sleep:

我們可以指定睡眠時間,即讓程序暫停指定時間運行,時間到了會繼續(xù)執(zhí)行代碼,如果時間未到我們想要換醒需要調(diào)用interrupt 方法來隨時喚醒即可。而調(diào)用interrupt 會使得sleep()方法拋出InterruptedException 異常,當sleep()方法拋出異常我們就中斷了sleep的方法,從而讓程序繼續(xù)運行下去。

wait:

調(diào)用該方法,可以導致線程進入等待阻塞狀態(tài),會一直等待直到它被其他線程通過notify或者notifyAll方法喚醒?;蛘咭部梢允褂?code>wait(long timeout)表示時間到了自動執(zhí)行,類似于sleep(long millis)。

notify():該方法會隨機選擇一個在該對象上調(diào)用wait方法的線程,解除其阻塞狀態(tài)。

notifyAll():該方法會喚醒所有的wait對象。

兩者的區(qū)別:

  • 兩者所屬的類不同:sleep是 Thread線程類的靜態(tài)方法;而wait是 Object類的方法。
  • 兩者是否是否鎖呢:sleep不釋放鎖;wait釋放鎖。
  • 兩者所使用的場景:sleep可以在任何需要的場景下調(diào)用;而wait必須使用在同步代碼塊或者同步方法中。
  • 兩者不同喚醒機制:sleep方法執(zhí)行睡眠時間完成后,線程會自動蘇醒;而wait方法被調(diào)用后,線程不會自動蘇醒,需要別的線程調(diào)用同一個對象上的 notify或者 notifyAll方法,或者可以使用wait(long timeout)超時后線程會自動蘇醒。

總結(jié):

這篇文章就到這里了,如果這篇文章對你也有所幫助,希望您能多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • 在Java的MyBatis框架中建立接口進行CRUD操作的方法

    在Java的MyBatis框架中建立接口進行CRUD操作的方法

    這篇文章主要介紹了在Java的MyBatis框架中建立接口進行CRUD操作的方法,CRUD是指在做計算處理時的增加(Create)、重新取得數(shù)據(jù)(Retrieve)、更新(Update)和刪除(Delete)幾個單詞的首字母簡寫,需要的朋友可以參考下
    2016-04-04
  • SpringBoot3.x打包Docker容器的實現(xiàn)

    SpringBoot3.x打包Docker容器的實現(xiàn)

    這篇文章主要介紹了SpringBoot3.x打包Docker容器的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • IDEA下從零開始搭建SpringBoot工程的方法步驟

    IDEA下從零開始搭建SpringBoot工程的方法步驟

    這篇文章主要介紹了IDEA下從零開始搭建SpringBoot工程的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • springboot實現(xiàn)配置兩個parent的方法

    springboot實現(xiàn)配置兩個parent的方法

    這篇文章主要介紹了springboot實現(xiàn)配置兩個parent的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java中的動態(tài)代理原理及實現(xiàn)

    Java中的動態(tài)代理原理及實現(xiàn)

    這篇文章主要介紹了Java中的動態(tài)代理原理及實現(xiàn),動態(tài)是相對于靜態(tài)而言,何為靜態(tài),即編碼時手動編寫代理類、委托類,而動態(tài)呢,是不編寫具體實現(xiàn)類,等到使用時,動態(tài)創(chuàng)建一個來實現(xiàn)代理的目的,需要的朋友可以參考下
    2023-12-12
  • 一文詳解Java抽象類到底有多抽象

    一文詳解Java抽象類到底有多抽象

    這篇文章主要介紹了一文詳解Java抽象類到底有多抽象,抽象方法所在的類必須是抽象類,子類若繼承了一個抽象類,就必須覆寫父類的所有抽象方法,這里的子類是普通類,是強制要求覆寫所有抽象方法,但是如果子類也是一個抽象類,那么就可以不覆寫
    2022-06-06
  • Java抽象類的構(gòu)造模板模式用法示例

    Java抽象類的構(gòu)造模板模式用法示例

    這篇文章主要介紹了Java抽象類的構(gòu)造模板模式用法,結(jié)合實例形式分析了java使用抽象類構(gòu)造模板模式相關(guān)操作技巧,需要的朋友可以參考下
    2019-09-09
  • java實現(xiàn)驗證碼小程序

    java實現(xiàn)驗證碼小程序

    這篇文章主要為大家詳細介紹了java實現(xiàn)驗證碼小程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • java進制轉(zhuǎn)換工具類實現(xiàn)減少參數(shù)長度

    java進制轉(zhuǎn)換工具類實現(xiàn)減少參數(shù)長度

    這篇文章主要為大家介紹了java進制轉(zhuǎn)換工具類實現(xiàn)減少參數(shù)長度示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Spring Cloud Feign原理詳解

    Spring Cloud Feign原理詳解

    Feign 主要是幫助我們方便進行rest api服務(wù)間的調(diào)用,本文從Spring Cloud對feign封裝的源碼中去了解其主要實現(xiàn)機制
    2021-06-06

最新評論

大埔县| 波密县| 屯留县| 海宁市| 察雅县| 开远市| 都江堰市| 图们市| 慈溪市| 四会市| 馆陶县| 唐河县| 博野县| 获嘉县| 镇原县| 上犹县| 尼玛县| 孟州市| 高青县| 连山| 句容市| 云安县| 岑溪市| 西藏| 当涂县| 横峰县| 马龙县| 木兰县| 兰坪| 清徐县| 枣阳市| 边坝县| 舞钢市| 马边| 舟山市| 临桂县| 衡水市| 中山市| 德清县| 乌兰县| 上虞市|