日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

并發(fā)編程快速入門

 印度阿三17 2019-07-10

1、線程與進(jìn)程的區(qū)別

進(jìn)程是所有線程的集合,每一個(gè)線程是進(jìn)程中的一條執(zhí)行路徑。

比方:通過查看 windows 任務(wù)管理器中的列表,我們可以把運(yùn)行在內(nèi)存中的 exe 文件理解成進(jìn)程,進(jìn)程是受操作系統(tǒng)管理的基本運(yùn)行單元。

2、為什么要使用多線程?

主要體現(xiàn)在多線程提高程序效率,但是需要注意,并不是使用了多線程就一定能提升性能,有的情況反而會(huì)降低性能。

多線程應(yīng)用場(chǎng)景:

2.1、避免阻塞

我們知道,在我們單線程中,代碼是順序執(zhí)行的,如果前面的操作發(fā)生了阻塞,那么就會(huì)影響到后面的操作,這時(shí)候可以采用多線程,可以理解成異步調(diào)用;其實(shí)前端里的 ajax 就是一個(gè)很好地例子,默認(rèn) ajax 是開啟異步的,調(diào)用時(shí)瀏覽器會(huì)啟一個(gè)新的線程,不阻塞當(dāng)前頁(yè)面的正常操作;

2.2、避免CPU空轉(zhuǎn)

以http server為例,如果只用單線程響應(yīng)HTTP請(qǐng)求,即處理完一條請(qǐng)求,再處理下一條請(qǐng)求的話,CPU會(huì)存在大量的閑置時(shí)間;

因?yàn)樘幚硪粭l請(qǐng)求,經(jīng)常涉及到RPC、數(shù)據(jù)庫(kù)訪問、磁盤IO等操作,這些操作的速度比CPU慢很多,而在等待這些響應(yīng)的時(shí)候,CPU卻不能去處理新的請(qǐng)求,因此http server的性能就很差;

所以很多web容器,都采用對(duì)每個(gè)請(qǐng)求創(chuàng)建新線程來響應(yīng)的方式實(shí)現(xiàn),這樣在等待請(qǐng)求A的IO操作的等待時(shí)間里,就可以去繼續(xù)處理請(qǐng)求B,對(duì)并發(fā)的響應(yīng)性就好了很多 。

3、多線程常見的兩種創(chuàng)建方式

3.1、繼承Thread類,重寫run方法
/**
 * author:  niceyoo
 * blog:    https://cnblogs.com/niceyoo
 * desc:
 */
public class ThreadDemo {
    public static void main(String[] args) {
        System.out.println("-----多線程創(chuàng)建開始-----");
        /* 1.創(chuàng)建一個(gè)線程*/
        CreateThread createThread = new CreateThread();
        /* 2.開始執(zhí)行線程 注意 開啟線程不是調(diào)用run方法,而是start方法*/
        System.out.println("-----多線程創(chuàng)建啟動(dòng)-----");
        createThread.start();
        System.out.println("-----多線程創(chuàng)建結(jié)束-----");
    }
}

class CreateThread extends Thread {

    /*run方法中編寫 多線程需要執(zhí)行的代碼*/
    @Override
    public void run() {
        for (int i = 0; i< 10; i  ) {
            System.out.println("i:"   i);
        }
    }
}

打印結(jié)果:

-----多線程創(chuàng)建開始-----
-----多線程創(chuàng)建啟動(dòng)-----
-----多線程創(chuàng)建結(jié)束-----
i:0
i:1
i:2
i:3
i:4
i:5
i:6
i:7
i:8
i:9

線程調(diào)用 start() 方法后,代碼并沒有從上往下執(zhí)行,而是有一條新的執(zhí)行分支。

注意:畫圖演示多線程不同執(zhí)行路徑。

3.2、實(shí)現(xiàn)Runnable接口,重寫run方法
/**
 * author:  niceyoo
 * blog:    https://cnblogs.com/niceyoo
 * desc:
 */
class CreateRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i< 10; i  ) {
            System.out.println("i:"   i);
        }
    }
}

public class ThreadDemo2 {
    public static void main(String[] args) {
        System.out.println("-----多線程創(chuàng)建開始-----");
        /* 1.創(chuàng)建一個(gè)線程 */
        CreateRunnable createThread = new CreateRunnable();
        /* 2.開始執(zhí)行線程 注意 開啟線程不是調(diào)用run方法,而是start方法 */
        System.out.println("-----多線程創(chuàng)建啟動(dòng)-----");
        Thread thread = new Thread(createThread);
        thread.start();
        System.out.println("-----多線程創(chuàng)建結(jié)束-----");
    }
}

打印結(jié)果:

-----多線程創(chuàng)建開始-----
-----多線程創(chuàng)建啟動(dòng)-----
-----多線程創(chuàng)建結(jié)束-----
i:0
i:1
i:2
i:3
i:4
i:5
i:6
i:7
i:8
i:9
使用繼承Thread類還是使用實(shí)現(xiàn)Runnable接口好?

使用實(shí)現(xiàn)Runnable接口好,繼承方式的擴(kuò)展性不強(qiáng),java總只支持單繼承,如果一個(gè)類繼承Thread就不能繼承其他的類了。

4、守護(hù)線程

java 中有兩種線程,一種是用戶線程,一種是守護(hù)線程。

  • 用戶線程:指用戶自定義創(chuàng)建的線程,主線程停止,用戶線程不會(huì)停止。

  • 守護(hù)線程:當(dāng)前進(jìn)程不存在或主線程停止,守護(hù)進(jìn)程也會(huì)被停止。

如何使用守護(hù)線程?

只需要調(diào)用 setDaemon(true) 方法即可設(shè)置為守護(hù)線程。

/**
 * author:  niceyoo
 * blog:    https://cnblogs.com/niceyoo
 * desc:
 */
public class DaemonThread {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {
                    }
                    System.out.println("我是子線程...");
                }
            }
        });
        thread.setDaemon(true);
        thread.start();
        for (int i = 0; i < 10; i  ) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {

            }
            System.out.println("我是主線程");
        }
        System.out.println("主線程執(zhí)行完畢!");
    }
}

運(yùn)行結(jié)果:

...
我是主線程
我是子線程...
我是主線程
主線程執(zhí)行完畢!

從運(yùn)行結(jié)果看到,main函數(shù)執(zhí)行完了,守護(hù)線程也跟著停止了。

5、多線程運(yùn)行狀態(tài)

線程從創(chuàng)建、運(yùn)行到結(jié)束,總是處于下面五個(gè)狀態(tài)之一:

新建狀態(tài)、就緒狀態(tài)、運(yùn)行狀態(tài)、阻塞狀態(tài)以及死亡狀態(tài)。

5.1、新建狀態(tài)

當(dāng)用new操作符創(chuàng)建一個(gè)線程時(shí), 例如new Thread?,線程還沒有開始運(yùn)行,此時(shí)線程處在新建狀態(tài)。 當(dāng)一個(gè)線程處于新生狀態(tài)時(shí),程序還沒有開始運(yùn)行線程中的代碼

5.2、就緒狀態(tài)

一個(gè)新創(chuàng)建的線程并不自動(dòng)開始運(yùn)行,要執(zhí)行線程,必須調(diào)用線程的start()方法。當(dāng)線程對(duì)象調(diào)用start()方法即啟動(dòng)了線程,start()方法創(chuàng)建線程運(yùn)行的系統(tǒng)資源,并調(diào)度線程運(yùn)行run()方法。當(dāng)start()方法返回后,線程就處于就緒狀態(tài)。

處于就緒狀態(tài)的線程并不一定立即運(yùn)行run()方法,線程還必須同其他線程競(jìng)爭(zhēng)CPU時(shí)間,只有獲得CPU時(shí)間才可以運(yùn)行線程。因?yàn)樵趩蜟PU的計(jì)算機(jī)系統(tǒng)中,不可能同時(shí)運(yùn)行多個(gè)線程,一個(gè)時(shí)刻僅有一個(gè)線程處于運(yùn)行狀態(tài)。因此此時(shí)可能有多個(gè)線程處于就緒狀態(tài)。對(duì)多個(gè)處于就緒狀態(tài)的線程是由Java運(yùn)行時(shí)系統(tǒng)的線程調(diào)度程序(thread scheduler)來調(diào)度的。

5.3、運(yùn)行狀態(tài)

當(dāng)線程獲得CPU時(shí)間后,它才進(jìn)入運(yùn)行狀態(tài),真正開始執(zhí)行run()方法.

5.4、阻塞狀態(tài)

線程運(yùn)行過程中,可能由于各種原因進(jìn)入阻塞狀態(tài):

  1. 線程通過調(diào)用sleep方法進(jìn)入睡眠狀態(tài);
  2. 線程調(diào)用一個(gè)在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會(huì)返回到它的調(diào)用者;
  3. 線程試圖得到一個(gè)鎖,而該鎖正被其他線程持有;
  4. 線程在等待某個(gè)觸發(fā)條件;
5.5、死亡狀態(tài)

有兩個(gè)原因會(huì)導(dǎo)致線程死亡:

  1. run方法正常退出而自然死亡,
  2. 一個(gè)未捕獲的異常終止了run方法而使線程猝死。

為了確定線程在當(dāng)前是否存活著(就是要么是可運(yùn)行的,要么是被阻塞了),需要使用 isAlive() 方法。如果是可運(yùn)行或被阻塞,這個(gè)方法返回true; 如果線程仍舊是new狀態(tài)且不是可運(yùn)行的, 或者線程死亡了,則返回false.

6、join()方法的作用

在多線程中也是有執(zhí)行的優(yōu)先級(jí)的,所謂的優(yōu)先級(jí),就是cpu是否格外關(guān)注這位小兄弟,優(yōu)先級(jí)越大,自然獲得的好處就越多。

當(dāng)在主線程當(dāng)中執(zhí)行到 小弟.join() 方法時(shí),就認(rèn)為主線程應(yīng)該把執(zhí)行權(quán)讓給 小弟。

舉一個(gè)例子:

創(chuàng)建一個(gè)線程,如何讓子線程執(zhí)行完畢后,主線程才能執(zhí)行呢?

public class ThreadDemo3 {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 10; i  ) {
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {

                    }
                    System.out.println(Thread.currentThread().getName()   "i:"   i);
                }
            }
        });
        t1.start();
        /* 當(dāng)在主線程當(dāng)中執(zhí)行到t1.join()方法時(shí),就認(rèn)為主線程應(yīng)該把執(zhí)行權(quán)讓給t1 */
        t1.join();
        for (int i = 0; i < 10; i  ) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {

            }
            System.out.println("main"   "i:"   i);
        }
    }
}

打印結(jié)果:

Thread-0i:0
Thread-0i:1
Thread-0i:2
Thread-0i:3
Thread-0i:4
Thread-0i:5
Thread-0i:6
Thread-0i:7
Thread-0i:8
Thread-0i:9
maini:0
maini:1
maini:2
maini:3
maini:4
maini:5
maini:6
maini:7
maini:8
maini:9

7、優(yōu)先級(jí)

雖然上邊在介紹 join 方法時(shí)提到了優(yōu)先級(jí),但是在使用 join() 方法后,該線程卻變成了完全主導(dǎo),這或許并不是你想要的結(jié)果。

現(xiàn)代操作系統(tǒng)基本采用時(shí)分的形式調(diào)度運(yùn)行的線程,線程分配得到的時(shí)間片的多少?zèng)Q定了線程使用處理器資源的多少,也對(duì)應(yīng)了線程優(yōu)先級(jí)這個(gè)概念。在JAVA線程中,通過一個(gè)int priority來控制優(yōu)先級(jí),范圍為1-10,其中10最高,默認(rèn)值為5。下面是源碼(基于1.8)中關(guān)于priority的一些量和方法。

class PrioritytThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i  ) {
            System.out.println(Thread.currentThread().toString()   "---i:"   i);
        }
    }
}

public class ThreadDemo4 {
    public static void main(String[] args) {
        PrioritytThread prioritytThread = new PrioritytThread();
        Thread t1 = new Thread(prioritytThread);
        Thread t2 = new Thread(prioritytThread);
        t1.start();
        /* 注意設(shè)置了優(yōu)先級(jí), 不代表每次都一定會(huì)被執(zhí)行。 只是CPU調(diào)度會(huì)有限分配 */
        t1.setPriority(10);
        t2.start();
    }
}

打印結(jié)果:

Thread[t1,10,main]---i:0
Thread[t1,10,main]---i:1
Thread[t1,10,main]---i:2
Thread[t1,10,main]---i:3
Thread[t1,10,main]---i:4
Thread[t1,10,main]---i:5
Thread[t1,10,main]---i:6
Thread[t1,10,main]---i:7
Thread[t1,10,main]---i:8
Thread[t1,10,main]---i:9
Thread[t2,5,main]---i:0
Thread[t2,5,main]---i:1
Thread[t2,5,main]---i:2
Thread[t2,5,main]---i:3
Thread[t2,5,main]---i:4
Thread[t2,5,main]---i:5
Thread[t2,5,main]---i:6
Thread[t2,5,main]---i:7
Thread[t2,5,main]---i:8
Thread[t2,5,main]---i:9

7、常見的面試題

進(jìn)程與線程的區(qū)別?

答:進(jìn)程是所有線程的集合,每一個(gè)線程是進(jìn)程中的一條執(zhí)行路徑。

為什么要用多線程?

答:提高程序效率

多線程創(chuàng)建方式?

答:繼承Thread或Runnable 接口。

使用繼承Thread類還是使用實(shí)現(xiàn)Runnable接口好?

答:實(shí)現(xiàn)Runnable接口好,繼承方式的擴(kuò)展性不強(qiáng),java總只支持單繼承,如果一個(gè)類繼承Thread就不能繼承其他的類了。

你在哪里用到了多線程?

答:主要能體現(xiàn)到多線程提高程序效率。

舉例:分批發(fā)送短信。

8、最后總結(jié)

我們了解了什么是線程,線程是一條執(zhí)行路徑,每個(gè)線程互不影響;

了解了什么是多線程,多線程在一個(gè)線程中,有多條不同的執(zhí)行路徑,并行執(zhí)行,目的為了提高程序效率。

了解了線程創(chuàng)建常見的兩種方式:繼承Thread類實(shí)現(xiàn)run方法,或者實(shí)現(xiàn)Runnable接口。

事實(shí)上,實(shí)際開發(fā)中這兩種方式并不常見,而是使用線程池來進(jìn)行管理。

了解了線程的幾種狀態(tài),新建、就緒、運(yùn)行、阻塞、死亡。

了解了線程里面也是有優(yōu)先級(jí)的,用數(shù)值1-10來記錄,默認(rèn)是5,最大是10,通過調(diào)用 setPriority(10) 來設(shè)置優(yōu)先級(jí),需要一提的是,并不是優(yōu)先級(jí)越大就一定要先執(zhí)行完,只是優(yōu)先執(zhí)行完的概率要大。

我創(chuàng)建了一個(gè)java相關(guān)的公眾號(hào),用來記錄自己的學(xué)習(xí)之路,感興趣的小伙伴可以關(guān)注一下微信公眾號(hào)哈:niceyoo

來源:https://www./content-1-314401.html

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多