Java多線程面試題整理

1.并發(fā)和并行有什么區(qū)別劫乱?

(來源——實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì))

并發(fā)偏重于多個(gè)任務(wù)交替執(zhí)行膊畴,而多個(gè)任務(wù)之間有可能還是串行的掘猿;而并行是真正意義上的同時(shí)執(zhí)行。
image

從嚴(yán)格意義.上來說唇跨,并行的多個(gè)任務(wù)是真的同時(shí)執(zhí)行稠通,而對(duì)于并發(fā)來說,這個(gè)過程只是交替的买猖,一會(huì)兒執(zhí)行任務(wù)A改橘,一會(huì)兒執(zhí)行任務(wù)B,系統(tǒng)會(huì)不停地在兩者之間切換。

實(shí)際上玉控,如果系統(tǒng)內(nèi)只有一個(gè)CPU,而使用多進(jìn)程或者多線程任務(wù)飞主,那么真實(shí)環(huán)境中這些任務(wù)不可能是真實(shí)并行的,畢竟一個(gè)CPU 一次只能執(zhí)行一條指令高诺,在這種情況下多進(jìn)程或者多線程就是并發(fā)的碌识,而不是并行的(操作系統(tǒng)會(huì)不停地切換多個(gè)任務(wù))。真實(shí)的并行也只可能出現(xiàn)在擁有多個(gè)CPU的系統(tǒng)中(比如多核CPU)虱而。.

2.線程和進(jìn)程的區(qū)別筏餐?

做個(gè)簡(jiǎn)單的比喻:進(jìn)程=火車,線程=車廂

線程在進(jìn)程下行進(jìn)(單純的車廂無法運(yùn)行)

一個(gè)進(jìn)程可以包含多個(gè)線程(一輛火車可以有多個(gè)車廂)

不同進(jìn)程間數(shù)據(jù)很難共享(一輛火車上的乘客很難換到另外一輛火車牡拇,比如站點(diǎn)換乘)

同一進(jìn)程下不同線程間數(shù)據(jù)很易共享(A車廂換到B車廂很容易)

進(jìn)程要比線程消耗更多的計(jì)算機(jī)資源(采用多列火車相比多個(gè)車廂更耗資源)

進(jìn)程間不會(huì)相互影響魁瞪,一個(gè)線程掛掉將導(dǎo)致整個(gè)進(jìn)程掛掉(一列火車不會(huì)影響到另外一列火車,但是如果一列火車上中間的一節(jié)車廂著火了惠呼,將影響到所有車廂)

進(jìn)程可以拓展到多機(jī)导俘,進(jìn)程最多適合多核(不同火車可以開在多個(gè)軌道上,同一火車的車廂不能在行進(jìn)的不同的軌道上)

進(jìn)程使用的內(nèi)存地址可以上鎖剔蹋,即一個(gè)線程使用某些共享內(nèi)存時(shí)旅薄,其他線程必須等它結(jié)束,才能使用這一塊內(nèi)存滩租。(比如火車上的洗手間)-"互斥鎖"

進(jìn)程使用的內(nèi)存地址可以限定使用量(比如火車上的餐廳赋秀,最多只允許多少人進(jìn)入,如果滿了需要在門口等律想,等有人出來了才能進(jìn)去)-“信號(hào)量”

轉(zhuǎn)自:https://www.zhihu.com/question/25532384/answer/411179772

3.守護(hù)線程是什么猎莲?

守護(hù)線程(daemon thread),是個(gè)服務(wù)線程技即,準(zhǔn)確地來說就是服務(wù)其他的線程著洼,類似垃圾回收線程。

4.創(chuàng)建線程有哪幾種方式而叼?

一身笤、繼承Thread類創(chuàng)建線程類

(1)繼承Thread類,并重寫run方法葵陵,該run方法的方法體就代表了線程要完成的任務(wù)液荸。因此把run()方法稱為執(zhí)行體。

(2)創(chuàng)建Thread子類的實(shí)例脱篙,即創(chuàng)建了線程對(duì)象娇钱。

(3)調(diào)用線程對(duì)象的start()方法來啟動(dòng)該線程。

package com.example.demo.thread;

public class MyThread extends Thread {

    int i = 0;

    @Override
    public void run() {
        for (; i < 100; i++) {
            System.out.println(getName() + "  " + i);
        }
    }

    public static void main(String[] args) {

        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "  : " + i);
            if (i == 50) {
                new MyThread().start();
                new MyThread().start();
            }
        }
    }
    
}

上述代碼中Thread.currentThread()方法返回當(dāng)前正在執(zhí)行的線程對(duì)象绊困。getName()方法返回調(diào)用該方法的線程的名字文搂。

二、通過Runnable接口創(chuàng)建線程類
(1)定義runnable接口的實(shí)現(xiàn)類秤朗,并重寫該接口的run()方法煤蹭,該run()方法的方法體同樣是該線程的線程執(zhí)行體。
(2)創(chuàng)建 Runnable實(shí)現(xiàn)類的實(shí)例取视,并依此實(shí)例作為Thread的target來創(chuàng)建Thread對(duì)象硝皂,該Thread對(duì)象才是真正的線程對(duì)象。
(3)調(diào)用線程對(duì)象的start()方法來啟動(dòng)該線程贫途。

package com.example.demo.thread;

public class MyRunnable implements Runnable {

    private int i;

    @Override
    public void run() {
        for (i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 20) {
                MyRunnable runnable = new MyRunnable();
                new Thread(runnable, "新線程1").start();
                new Thread(runnable, "新線程2").start();
            }
        }

    }
}

三吧彪、通過Callable和Future創(chuàng)建線程
(1)創(chuàng)建Callable接口的實(shí)現(xiàn)類,并實(shí)現(xiàn)call()方法丢早,該call()方法將作為線程執(zhí)行體姨裸,并且有返回值。
(2)創(chuàng)建Callable實(shí)現(xiàn)類的實(shí)例怨酝,使用FutureTask類來包裝Callable對(duì)象傀缩,該FutureTask對(duì)象封裝了該Callable對(duì)象的call()方法的返回值。
(3)使用FutureTask對(duì)象作為Thread對(duì)象的target創(chuàng)建并啟動(dòng)新線程农猬。
(4)調(diào)用FutureTask對(duì)象的get()方法來獲得子線程執(zhí)行結(jié)束后的返回值

package com.example.demo.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MyCallable implements Callable<Integer> {

    public static void main(String[] args) {
        MyCallable callable = new MyCallable();
        FutureTask<Integer> ft = new FutureTask<>(callable);
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " 的循環(huán)變量i的值" + i);
            if (i == 20) {
                new Thread(ft, "有返回值的線程").start();
            }
        }
        try {
            System.out.println("子線程的返回值:" + ft.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }

    @Override
    public Integer call() throws Exception {
        int i = 0;
        for (; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
        return i;
    }
}

采用實(shí)現(xiàn)Runnable赡艰、Callable接口的方式創(chuàng)見多線程時(shí),優(yōu)勢(shì)是:
線程類只是實(shí)現(xiàn)了Runnable接口或Callable接口斤葱,還可以繼承其他類慷垮。
在這種方式下揖闸,多個(gè)線程可以共享同一個(gè)target對(duì)象,所以非常適合多個(gè)相同線程來處理同一份資源的情況料身,從而可以將CPU汤纸、代碼和數(shù)據(jù)分開,形成清晰的模型芹血,較好地體現(xiàn)了面向?qū)ο蟮乃枷搿?br> 劣勢(shì)是:
編程稍微復(fù)雜贮泞,如果要訪問當(dāng)前線程,則必須使用Thread.currentThread()方法幔烛。
使用繼承Thread類的方式創(chuàng)建多線程時(shí)優(yōu)勢(shì)是:
編寫簡(jiǎn)單啃擦,如果需要訪問當(dāng)前線程,則無需使用Thread.currentThread()方法饿悬,直接使用this即可獲得當(dāng)前線程令蛉。
劣勢(shì)是:
線程類已經(jīng)繼承了Thread類,所以不能再繼承其他父類乡恕。

5.說一下 runnable 和 callable 有什么區(qū)別言询?

1)Runnable提供run方法,不會(huì)拋出異常傲宜,只能在run方法內(nèi)部處理異常运杭。Callable提供call方法,直接拋出Exception異常函卒,也就是你不會(huì)因?yàn)閏all方法內(nèi)部出現(xiàn)檢查型異常而不知所措辆憔,完全可以拋出即可。
2)Runnable的run方法無返回值报嵌,Callable的call方法提供返回值用來表示任務(wù)運(yùn)行的結(jié)果
3)Runnable可以作為Thread構(gòu)造器的參數(shù)虱咧,通過開啟新的線程來執(zhí)行,也可以通過線程池來執(zhí)行锚国。而Callable只能通過線程池執(zhí)行腕巡。

6.線程的生命周期?

  • 新建 (New) :當(dāng)程序使用 new 關(guān)鍵字創(chuàng)建了一個(gè)線程后血筑。此時(shí)由 JVM 為其分配內(nèi)存绘沉,并初始化其成員變量的值。
  • 可運(yùn)行/就緒(Runnable):當(dāng)調(diào)用了 start()方法豺总,線程就處于可運(yùn)行狀態(tài)车伞。Java 虛擬機(jī)會(huì)為其創(chuàng)建方法調(diào)用棧可程序計(jì)數(shù)器喻喳,等到調(diào)度運(yùn)行另玖。
  • 運(yùn)行狀態(tài)(Running):處于可運(yùn)行狀態(tài)的線程獲得 CPU 分片后,執(zhí)行 run()方法。
  • 阻塞(Blocked):當(dāng)處于運(yùn)行狀態(tài)的線程失去了所占有的資源谦去。
  • 死亡(Dead):程序正常完成慷丽、或者線程拋出一個(gè)未捕獲的 Exception 貨或 Error■蓿或者調(diào)用線程的中斷方法盈魁。

不要試圖對(duì)一個(gè)已經(jīng)死亡的線程調(diào)用 start() 方法讓它重新啟動(dòng),死亡就是死亡了窃诉,該線程不可再次作為線程執(zhí)行。

image.png

7.sleep() 和 wait() 有什么區(qū)別赤套?

sleep是Thread類的方法,wait是Object類中定義的方法

1飘痛、sleep就是正在執(zhí)行的線程主動(dòng)讓出cpu,cpu去執(zhí)行其他線程容握,在sleep指定的時(shí)間過后宣脉,cpu才會(huì)回到這個(gè)線程上繼續(xù)往下執(zhí)行
2、如果當(dāng)前線程進(jìn)入了同步鎖(synchronized)剔氏,sleep方法并不會(huì)釋放鎖塑猖,即使當(dāng)前線程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線程也無法得到執(zhí)行谈跛。
2羊苟、wait是指在一個(gè)已經(jīng)進(jìn)入了同步鎖的線程內(nèi),讓自己暫時(shí)讓出同步鎖感憾,以便其他正在等待此鎖的線程可以得到同步鎖并運(yùn)行
2.2蜡励、只有其他線程調(diào)用了notify方法,調(diào)用wait方法的線程就會(huì)解除wait狀態(tài)和程序可以再次得到鎖后繼續(xù)向下運(yùn)行阻桅。

【注意】notify并不釋放鎖凉倚,只是告訴調(diào)用過wait方法的線程可以去參與獲得鎖的競(jìng)爭(zhēng)了,但不是馬上得到鎖嫂沉,因?yàn)殒i還在別人手里稽寒,別人還沒釋放。如果notify方法后面的代碼還有很多趟章,需要這些代碼執(zhí)行完后才會(huì)釋放鎖
【總結(jié)】notify只是告訴wait()的線程什么時(shí)候可以去繼續(xù)去申請(qǐng)鎖了

package com.example.demo.thread;

public class MultiThread {

    private static class Thread1 implements Runnable {
        @Override
        public void run() {
            //由于 Thread1和下面Thread2內(nèi)部run方法要用同一對(duì)象作為監(jiān)視器杏糙,
            // 如果用this則Thread1和Threa2的this不是同一對(duì)象所以用MultiThread.class這個(gè)字節(jié)碼對(duì)象,
            // 當(dāng)前虛擬機(jī)里引用這個(gè)變量時(shí)指向的都是同一個(gè)對(duì)象
            synchronized (MultiThread.class) {
                System.out.println("enter thread1 ...");
                System.out.println("thread1 is waiting");

                try {
                    //釋放鎖有兩種方式:
                    // (1)程序自然離開監(jiān)視器的范圍尤揣,即離開synchronized關(guān)鍵字管轄的代碼范圍
                    //(2)在synchronized關(guān)鍵字管轄的代碼內(nèi)部調(diào)用監(jiān)視器對(duì)象的wait()方法搔啊。
                    // 這里使用wait方法
                    MultiThread.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("thread1 is going on ...");
                System.out.println("thread1 is being over!");
            }
        }

    }

    private static class Thread2 implements Runnable {
        @Override
        public void run() {
            //notify方法并不釋放鎖,即使thread2調(diào)用了下面的sleep方法休息10ms北戏,但thread1仍然不會(huì)執(zhí)行
            //因?yàn)閠hread2沒有釋放鎖负芋,所以Thread1得不到鎖而無法執(zhí)行
            synchronized (MultiThread.class) {
                System.out.println("enter thread2 ...");
                System.out.println("thread2 notify other thread can release wait status ...");
                MultiThread.class.notify();
                System.out.println("thread2 is sleeping ten millisecond ...");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread2 is going on ...");
                System.out.println("thread2 is being over!");
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new Thread1()).start();
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(new Thread2()).start();
    }

}
執(zhí)行結(jié)果.png

【總結(jié):】首先先執(zhí)行了thread1,打印兩句話之后調(diào)用了wait方法,讓出了本鎖,然后往下執(zhí)行旧蛾,到線程thread2莽龟,它確實(shí)獲得到了本鎖,才會(huì)執(zhí)行下面的語句锨天,證明了wait方法確實(shí)是讓出了本鎖毯盈。然后打印了兩句話,調(diào)用了notify()方法病袄,告知thread1你可以去執(zhí)行了搂赋。但是此時(shí)thread1沒有鎖,鎖被thread2占用了益缠。thread2繼續(xù)執(zhí)行脑奠。打印一句話之后,調(diào)用sleep()方法讓出cpu幅慌,但是它不讓出鎖宋欺,所以thread1還是拿不到鎖,執(zhí)行不了胰伍,thread2睡眠完了之后齿诞,繼續(xù)往下打印兩句話,等執(zhí)行完成之后讓出改鎖骂租,thread1在繼續(xù)執(zhí)行祷杈。結(jié)果打印如上。

8.線程的 run()和 start()有什么區(qū)別渗饮?

1.start()方法來啟動(dòng)線程吠式,真正實(shí)現(xiàn)了多線程運(yùn)行。這時(shí)無需等待run方法體代碼執(zhí)行完畢抽米,可以直接繼續(xù)執(zhí)行下面的代碼特占;通過調(diào)用Thread類的start()方法來啟動(dòng)一個(gè)線程, 這時(shí)此線程是處于就緒狀態(tài)云茸, 并沒有運(yùn)行是目。 然后通過此Thread類調(diào)用方法run()來完成其運(yùn)行操作的, 這里方法run()稱為線程體标捺,它包含了要執(zhí)行的這個(gè)線程的內(nèi)容懊纳, run()方法運(yùn)行結(jié)束, 此線程終止亡容。然后CPU再調(diào)度其它線程嗤疯。
2.run()方法當(dāng)作普通方法的方式調(diào)用。程序還是要順序執(zhí)行闺兢,要等待run方法體執(zhí)行完畢后茂缚,才可繼續(xù)執(zhí)行下面的代碼; 程序中只有主線程這一個(gè)線程, 其程序執(zhí)行路徑還是只有一條脚囊, 這樣就沒有達(dá)到多線程的目的龟糕。

1、繼承 java.lang.Thread 類悔耘;

2讲岁、實(shí)現(xiàn) java.lang.Runnable接口;

其中 Thread 類也是實(shí)現(xiàn)了 Runnable 接口衬以,而 Runnable 接口定義了唯一的一個(gè) run() 方法缓艳,所以基于 Thread 和 Runnable 創(chuàng)建多線程都需要實(shí)現(xiàn) run() 方法,是多線程真正運(yùn)行的主方法看峻。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

而 start() 方法則是 Thread 類的方法郎任,用來異步啟動(dòng)一個(gè)線程,然后主線程立刻返回备籽。該啟動(dòng)的線程不會(huì)馬上運(yùn)行,會(huì)放到等待隊(duì)列中等待 CPU 調(diào)度分井,只有線程真正被 CPU 調(diào)度時(shí)才會(huì)調(diào)用 run() 方法執(zhí)行车猬。

那么你會(huì)問了,為什么要有兩個(gè)方法尺锚,直接用一個(gè) run() 方法不就行了嗎V槿颉? 還真不行瘫辩,如果直接調(diào)用 run() 方法伏嗜,那就等于調(diào)用了一個(gè)普通的同步方法,達(dá)不到多線程運(yùn)行的異步執(zhí)行伐厌,來看下面的例子承绸。

public static void main(String[] args) {
    Thread thread = new Thread(() -> {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Java技術(shù)棧");
    });

    long start = System.currentTimeMillis();
    thread.start();
    System.out.println(System.currentTimeMillis() - start);

    start = System.currentTimeMillis();
    thread.run();
    System.out.println(System.currentTimeMillis() - start);
}

程序輸出:
0
Java技術(shù)棧
3000
Java技術(shù)棧

從程序輸出結(jié)果可以看出,啟動(dòng) start 方法前后只用了 0 毫秒挣轨,而啟動(dòng) run 方法則阻塞了 3000 毫秒等程序執(zhí)行完再繼續(xù)執(zhí)行军熏,這就是同步與異步的一個(gè)最重要的區(qū)別。

9.線程池都有哪些狀態(tài)卷扮?

1.RUNNING:這是最正常的狀態(tài)荡澎,接受新的任務(wù),處理等待隊(duì)列中的任務(wù)晤锹。線程池的初始化狀態(tài)是RUNNING摩幔。線程池被一旦被創(chuàng)建,就處于RUNNING狀態(tài)鞭铆,并且線程池中的任務(wù)數(shù)為0或衡。

2.SHUTDOWN:不接受新的任務(wù)提交,但是會(huì)繼續(xù)處理等待隊(duì)列中的任務(wù)。調(diào)用線程池的shutdown()方法時(shí)薇宠,線程池由RUNNING -> SHUTDOWN偷办。

3.STOP:不接受新的任務(wù)提交,不再處理等待隊(duì)列中的任務(wù)澄港,中斷正在執(zhí)行任務(wù)的線程椒涯。調(diào)用線程池的shutdownNow()方法時(shí),線程池由(RUNNING or SHUTDOWN ) -> STOP回梧。

4.TIDYING:所有的任務(wù)都銷毀了废岂,workCount 為 0,線程池的狀態(tài)在轉(zhuǎn)換為 TIDYING 狀態(tài)時(shí)狱意,會(huì)執(zhí)行鉤子方法 terminated()湖苞。因?yàn)閠erminated()在ThreadPoolExecutor類中是空的,所以用戶想在線程池變?yōu)門IDYING時(shí)進(jìn)行相應(yīng)的處理详囤;可以通過重載terminated()函數(shù)來實(shí)現(xiàn)财骨。

當(dāng)線程池在SHUTDOWN狀態(tài)下,阻塞隊(duì)列為空并且線程池中執(zhí)行的任務(wù)也為空時(shí)藏姐,就會(huì)由 SHUTDOWN -> TIDYING隆箩。

當(dāng)線程池在STOP狀態(tài)下,線程池中執(zhí)行的任務(wù)為空時(shí)羔杨,就會(huì)由STOP -> TIDYING捌臊。

5.TERMINATED:線程池處在TIDYING狀態(tài)時(shí),執(zhí)行完terminated()之后兜材,就會(huì)由 TIDYING -> TERMINATED理澎。

10.多線程鎖的升級(jí)原理是什么?

鎖的級(jí)別從低到高:

無鎖 -> 偏向鎖 -> 輕量級(jí)鎖 -> 重量級(jí)鎖

鎖分級(jí)別原因:

沒有優(yōu)化以前曙寡,sychronized是重量級(jí)鎖(悲觀鎖)糠爬,使用 wait 和 notify、notifyAll 來切換線程狀態(tài)非常消耗系統(tǒng)資源举庶;線程的掛起和喚醒間隔很短暫秩铆,這樣很浪費(fèi)資源,影響性能灯变。所以 JVM 對(duì) sychronized 關(guān)鍵字進(jìn)行了優(yōu)化殴玛,把鎖分為 無鎖、偏向鎖添祸、輕量級(jí)鎖滚粟、重量級(jí)鎖 狀態(tài)。

無鎖:沒有對(duì)資源進(jìn)行鎖定刃泌,所有的線程都能訪問并修改同一個(gè)資源凡壤,但同時(shí)只有一個(gè)線程能修改成功署尤,其他修改失敗的線程會(huì)不斷重試直到修改成功。

偏向鎖:對(duì)象的代碼一直被同一線程執(zhí)行亚侠,不存在多個(gè)線程競(jìng)爭(zhēng)曹体,該線程在后續(xù)的執(zhí)行中自動(dòng)獲取鎖,降低獲取鎖帶來的性能開銷硝烂。偏向鎖箕别,指的就是偏向第一個(gè)加鎖線程,該線程是不會(huì)主動(dòng)釋放偏向鎖的滞谢,只有當(dāng)其他線程嘗試競(jìng)爭(zhēng)偏向鎖才會(huì)被釋放串稀。

偏向鎖的撤銷,需要在某個(gè)時(shí)間點(diǎn)上沒有字節(jié)碼正在執(zhí)行時(shí)狮杨,先暫停擁有偏向鎖的線程母截,然后判斷鎖對(duì)象是否處于被鎖定狀態(tài)。如果線程不處于活動(dòng)狀態(tài)橄教,則將對(duì)象頭設(shè)置成無鎖狀態(tài)清寇,并撤銷偏向鎖;

如果線程處于活動(dòng)狀態(tài)护蝶,升級(jí)為輕量級(jí)鎖的狀態(tài)华烟。

輕量級(jí)鎖:輕量級(jí)鎖是指當(dāng)鎖是偏向鎖的時(shí)候,被第二個(gè)線程 B 所訪問滓走,此時(shí)偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖,線程 B 會(huì)通過自旋的形式嘗試獲取鎖帽馋,線程不會(huì)阻塞搅方,從而提高性能。

當(dāng)前只有一個(gè)等待線程绽族,則該線程將通過自旋進(jìn)行等待姨涡。但是當(dāng)自旋超過一定的次數(shù)時(shí),輕量級(jí)鎖便會(huì)升級(jí)為重量級(jí)鎖吧慢;當(dāng)一個(gè)線程已持有鎖涛漂,另一個(gè)線程在自旋,而此時(shí)又有第三個(gè)線程來訪時(shí)检诗,輕量級(jí)鎖也會(huì)升級(jí)為重量級(jí)鎖匈仗。

重量級(jí)鎖:指當(dāng)有一個(gè)線程獲取鎖之后,其余所有等待獲取該鎖的線程都會(huì)處于阻塞狀態(tài)逢慌。

重量級(jí)鎖通過對(duì)象內(nèi)部的監(jiān)視器(monitor)實(shí)現(xiàn)悠轩,而其中 monitor 的本質(zhì)是依賴于底層操作系統(tǒng)的 Mutex Lock 實(shí)現(xiàn),操作系統(tǒng)實(shí)現(xiàn)線程之間的切換需要從用戶態(tài)切換到內(nèi)核態(tài)攻泼,切換成本非常高火架。

11.什么是死鎖鉴象?

線程死鎖是指由于兩個(gè)或者多個(gè)線程互相持有對(duì)方所需要的資源,導(dǎo)致這些線程處于等待狀態(tài)何鸡,無法繼續(xù)執(zhí)行纺弊。當(dāng)線程進(jìn)入對(duì)象的synchronized代碼塊時(shí),便占有了資源骡男,直到它退出該代碼塊或者調(diào)用wait方法淆游,才釋放資源,在此期間洞翩,其他線程將不能進(jìn)入該代碼塊稽犁。當(dāng)線程互相持有對(duì)方所需要的資源時(shí),會(huì)互相等待對(duì)方釋放資源骚亿,如果線程都不主動(dòng)釋放所占有的資源已亥,將產(chǎn)生死鎖。

當(dāng)然死鎖的產(chǎn)生是必須要滿足一些特定條件的:

1.互斥條件:進(jìn)程對(duì)于所分配到的資源具有排它性来屠,即一個(gè)資源只能被一個(gè)進(jìn)程占用虑椎,直到被該進(jìn)程釋放
2.請(qǐng)求和保持條件:一個(gè)進(jìn)程因請(qǐng)求被占用資源而發(fā)生阻塞時(shí),對(duì)已獲得的資源保持不放俱笛。
3.不剝奪條件:任何一個(gè)資源在沒被該進(jìn)程釋放之前捆姜,任何其他進(jìn)程都無法對(duì)他剝奪占用
4.循環(huán)等待條件:當(dāng)發(fā)生死鎖時(shí),所等待的進(jìn)程必定會(huì)形成一個(gè)環(huán)路(類似于死循環(huán))迎膜,造成永久阻塞泥技。

12.死鎖是什么?如何避免死鎖磕仅?

http://www.reibang.com/p/44125bb12ebf

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末珊豹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子榕订,更是在濱河造成了極大的恐慌店茶,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劫恒,死亡現(xiàn)場(chǎng)離奇詭異贩幻,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)两嘴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門丛楚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人憔辫,你說我怎么就攤上這事鸯檬。” “怎么了螺垢?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵喧务,是天一觀的道長(zhǎng)赖歌。 經(jīng)常有香客問我,道長(zhǎng)功茴,這世上最難降的妖魔是什么庐冯? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮坎穿,結(jié)果婚禮上展父,老公的妹妹穿的比我還像新娘。我一直安慰自己玲昧,他們只是感情好栖茉,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著孵延,像睡著了一般吕漂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尘应,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天惶凝,我揣著相機(jī)與錄音,去河邊找鬼犬钢。 笑死苍鲜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的玷犹。 我是一名探鬼主播混滔,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恶座,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體添瓷,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡每庆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鹅经。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寂呛。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瘾晃,靈堂內(nèi)的尸體忽然破棺而出贷痪,到底是詐尸還是另有隱情,我是刑警寧澤蹦误,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布劫拢,位于F島的核電站肉津,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏舱沧。R本人自食惡果不足惜妹沙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望熟吏。 院中可真熱鬧距糖,春花似錦、人聲如沸牵寺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帽氓。三九已至趣斤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間杏节,已是汗流浹背唬渗。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奋渔,地道東北人镊逝。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嫉鲸,于是被迫代替她去往敵國(guó)和親撑蒜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359