日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

一句話總結(jié)就是:引入線程前,進(jìn)程是資源分配和獨(dú)立調(diào)度的基本單位。引入線程后,進(jìn)程是資源分配的基本單位,線程是獨(dú)立調(diào)度的基本單位,線程也是進(jìn)程中的?個(gè)執(zhí)?單元。

一、摘要

在很多場(chǎng)景下,我們經(jīng)常聽到采用多線程編程,能顯著的提升程序的執(zhí)行效率。例如執(zhí)行大批量數(shù)據(jù)的插入操作,采用單線程編程進(jìn)行插入可能需要 30 分鐘,采用多線程編程進(jìn)行插入可能只需要 5 分鐘就夠了。

既然多線程編程技術(shù)如此厲害,那什么是多線程呢?

在介紹多線程之前,我們還得先講講進(jìn)程和線程的概念。

二、進(jìn)程和線程

2.1、什么是進(jìn)程?

從計(jì)算機(jī)角度來(lái)講,進(jìn)程是操作系統(tǒng)中的基本執(zhí)行單元,也是操作系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,并且進(jìn)程之間相互獨(dú)立,互不干擾。

例如,我們windows電腦中的 Chrome 瀏覽器是一個(gè)進(jìn)程、WeChat 也是一個(gè)進(jìn)程,正在操作系統(tǒng)中運(yùn)行的.exe都可以理解為一個(gè)進(jìn)程。

圖片圖片

2.2、什么是線程?

關(guān)于線程,比較官方的定義是,線程是進(jìn)程中的?個(gè)執(zhí)?單元,也是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,負(fù)責(zé)當(dāng)前進(jìn)程中程序的執(zhí)?。同時(shí)?個(gè)進(jìn)程中?少有?個(gè)線程,?個(gè)進(jìn)程中也可以有多個(gè)線程,它們共享這個(gè)進(jìn)程的資源,擁有多個(gè)線程的程序,我們也稱為多線程編程。

舉個(gè)例子,Chrome 瀏覽器和 WeChat 是兩個(gè)進(jìn)程,Chrome 瀏覽器進(jìn)程里面有很多線程,例如 HTTP 請(qǐng)求線程、事件響應(yīng)線程、渲染線程等等,線程的并發(fā)執(zhí)行使得在瀏覽器中點(diǎn)擊一個(gè)新鏈接從而發(fā)起 HTTP 請(qǐng)求時(shí),瀏覽器還可以響應(yīng)用戶的其它事件。

2.3、進(jìn)程和線程的關(guān)系

關(guān)于進(jìn)程和線程,可能上面的解釋過(guò)于抽象,還是很難理解,下面是一段出自阮一峰老師博客文章的介紹,可能描述不是非常嚴(yán)謹(jǐn),但是足夠形象,有助于我們對(duì)它們關(guān)系的理解。

1.我們都知道,計(jì)算機(jī)的核心是 CPU,它承擔(dān)了所有的計(jì)算任務(wù)。它就像一座工廠,時(shí)刻在運(yùn)行;(CPU 類似于工廠)

2.假定工廠的電力有限,一次只能供給一個(gè)車間使用。也就是說(shuō),一個(gè)車間開工的時(shí)候,其他車間都必須停工。背后的含義就是,單個(gè) CPU 一次只能運(yùn)行一個(gè)任務(wù);

3.進(jìn)程就好比工廠的車間,它代表 CPU 所能處理的單個(gè)任務(wù)。任一時(shí)刻,CPU 總是運(yùn)行一個(gè)進(jìn)程,其他進(jìn)程處于非運(yùn)行狀態(tài);(進(jìn)程類似于車間)

4.一個(gè)車間里,可以有很多工人。他們協(xié)同完成一個(gè)任務(wù);

5.線程就好比車間里的工人。一個(gè)進(jìn)程可以包括多個(gè)線程;(線程類似于工人)

6.車間的空間是工人們共享的,比如許多房間是每個(gè)工人都可以進(jìn)出的。這象征一個(gè)進(jìn)程的內(nèi)存空間是共享的,每個(gè)線程都可以使用這些共享內(nèi)存;(每個(gè)線程共享進(jìn)程下的內(nèi)存資源)

7.一個(gè)防止他人進(jìn)入的簡(jiǎn)單方法,就是門口加一把鎖。先到的人鎖上門,后到的人看到上鎖,就在門口排隊(duì),等鎖打開再進(jìn)去。這就叫"互斥鎖"(Mutual exclusion,縮寫 Mutex),防止多個(gè)線程同時(shí)讀寫某一塊內(nèi)存區(qū)域;(多個(gè)線程下可以通過(guò)互斥鎖,實(shí)現(xiàn)資源獨(dú)占)

8.還有些房間,可以同時(shí)容納 n 個(gè)人,比如廚房。也就是說(shuō),如果人數(shù)大于 n,多出來(lái)的人只能在外面等著。這好比某些內(nèi)存區(qū)域,只能供給固定數(shù)目的線程使用;

9.這時(shí)的解決方法,就是在門口掛 n 把鑰匙。進(jìn)去的人就取一把鑰匙,出來(lái)時(shí)再把鑰匙掛回原處。后到的人發(fā)現(xiàn)鑰匙架空了,就知道必須在門口排隊(duì)等著了。這種做法叫做 "信號(hào)量"(Semaphore),用來(lái)保證多個(gè)線程不會(huì)互相沖突。(多個(gè)線程下可以通過(guò)信號(hào)量,實(shí)現(xiàn)互不沖突)

不難看出,互斥鎖 Mutex 是信號(hào)量 semaphore 的一種特殊情況(n = 1時(shí))。也就是說(shuō),完全可以用后者替代前者。但是,因?yàn)?Mutex 較為簡(jiǎn)單,且效率高,所以在必須保證資源獨(dú)占的情況下,還是采用這種方式。

2.4、為什么要引入線程?

早期的操作系統(tǒng)都是以進(jìn)程作為獨(dú)立運(yùn)行的基本單位的,直到后期計(jì)算機(jī)科學(xué)家們又提出了更小的能獨(dú)立運(yùn)行的基本單位,也就是線程。

那為什么要引入線程呢?我們只需要記住這句話:線程又稱為迷你進(jìn)程,但是它比進(jìn)程更容易創(chuàng)建,也更容易撤銷。

引入線程之后,可以將復(fù)雜的操作進(jìn)一步分解,讓程序的執(zhí)行效率進(jìn)一步提升。

舉個(gè)例子,進(jìn)程就如同一個(gè)隨時(shí)背著糧草和機(jī)槍的士兵,這樣肯定會(huì)造成士兵的執(zhí)行戰(zhàn)斗的速度。因此,一個(gè)簡(jiǎn)單想法就是:分配兩個(gè)人來(lái)執(zhí)行,一個(gè)士兵負(fù)責(zé)隨時(shí)背著糧草,另一個(gè)士兵負(fù)責(zé)抗機(jī)槍戰(zhàn)斗,這樣執(zhí)行戰(zhàn)斗的速度會(huì)大幅提升。這些輕裝上陣的士兵,可以理解為我們上文提到的線程!

從計(jì)算機(jī)角度來(lái)說(shuō),由于創(chuàng)建或撤銷進(jìn)程時(shí),系統(tǒng)都要為之分配或回收資源,如內(nèi)存空間、I/O 設(shè)備等,需要較大的時(shí)間和空間開銷。

為了減少進(jìn)程切換的開銷,把進(jìn)程作為資源分配單位和調(diào)度單位這兩個(gè)屬性分開處理,即進(jìn)程還是作為資源分配的基本單位,但是把調(diào)度執(zhí)行與切換的責(zé)任交給線程,即線程成為獨(dú)立調(diào)度的基本單位,它比進(jìn)程更容易(更快)創(chuàng)建,也更容易撤銷。

一句話總結(jié)就是:引入線程前,進(jìn)程是資源分配和獨(dú)立調(diào)度的基本單位。引入線程后,進(jìn)程是資源分配的基本單位,線程是獨(dú)立調(diào)度的基本單位,線程也是進(jìn)程中的?個(gè)執(zhí)?單元。

三、創(chuàng)建線程的方式

在 JAVA 里面,創(chuàng)建線程有以下兩種方式:

  • 繼承java.lang.Thread類,重寫run()方法
  • 實(shí)現(xiàn)java.lang.Runnable接口,然后通過(guò)一個(gè)java.lang.Thread類來(lái)啟動(dòng)

不管是哪種方式,所有的線程對(duì)象都必須是Thread類或其?類的實(shí)例,每個(gè)線程的作?是完成?定的任務(wù),實(shí)際上就是執(zhí)??段程序流,即?段順序執(zhí)?的代碼,任務(wù)執(zhí)行完畢之后就結(jié)束了。

在 Java 中,通過(guò)Thread類來(lái)創(chuàng)建并啟動(dòng)線程的步驟如下:

  • 1.定義Thread類的?類,并重寫該類的run()方法
  • 2.通過(guò)Thread子類,初始化線程對(duì)象
  • 3.通過(guò)線程對(duì)象,調(diào)用start()方法啟動(dòng)線程

下面我們具體來(lái)看看創(chuàng)建線程的代碼實(shí)踐。

3.1、繼承 Thread 類,重寫 run 方法介紹

/**
 * 創(chuàng)建一個(gè) Thread 子類
 */
public class Thread0 extends Thread {

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date());
            System.out.println(time + " 當(dāng)前線程:" + Thread.currentThread().getName() + ",正在運(yùn)行");
        }
    }
}
 
/**
 * 創(chuàng)建一個(gè)測(cè)試類
 */
public class ThreadTest0 {

    public static void mAIn(String[] args) {
        // 初始化一個(gè)線程對(duì)象,然后啟動(dòng)線程
        Thread0 thread0 = new Thread0();
        thread0.start();

        for (int i = 0; i < 5; i++) {
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date());
            System.out.println(time + " 當(dāng)前線程:" + Thread.currentThread().getName() + ",正在運(yùn)行");
        }
    }
}

輸出結(jié)果:

2023-08-23 17:58:03:726 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 17:58:03:727 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 17:58:03:726 當(dāng)前線程:main,正在運(yùn)行
2023-08-23 17:58:03:727 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 17:58:03:727 當(dāng)前線程:main,正在運(yùn)行
2023-08-23 17:58:03:728 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 17:58:03:728 當(dāng)前線程:main,正在運(yùn)行
2023-08-23 17:58:03:728 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 17:58:03:728 當(dāng)前線程:main,正在運(yùn)行
2023-08-23 17:58:03:728 當(dāng)前線程:main,正在運(yùn)行

從執(zhí)行時(shí)間上可以看到,main線程和Thread-0線程交替運(yùn)行,效果十分明顯!

所謂的多線程,其實(shí)就是兩個(gè)及以上線程的代碼可以同時(shí)運(yùn)行,而不必一個(gè)線程需要等待另一個(gè)線程內(nèi)的代碼執(zhí)行完才可以運(yùn)行。

對(duì)于單核 CPU 來(lái)說(shuō),是無(wú)法做到真正的多線程的;但是對(duì)于多核 CPU 來(lái)說(shuō),在一段時(shí)間內(nèi),可以執(zhí)行多個(gè)任務(wù)的,由于 CPU 執(zhí)行代碼時(shí)間很快,所以兩個(gè)線程的代碼交替執(zhí)行看起來(lái)像是同時(shí)執(zhí)行的一樣,具體執(zhí)行某段代碼多少時(shí)間,就和分時(shí)機(jī)制系統(tǒng)有關(guān)了。

分時(shí)機(jī)制系統(tǒng),簡(jiǎn)單的說(shuō),就是將 CPU 時(shí)間劃分為多個(gè)時(shí)間片,操作系統(tǒng)以時(shí)間片為單位來(lái)執(zhí)行各個(gè)線程的代碼,越好的 CPU 分出的時(shí)間片越小。

例如某個(gè)時(shí)段, CPU 將 1 秒劃分成 50 個(gè)時(shí)間片,1 個(gè)時(shí)間片耗時(shí) 20 ms,每個(gè)時(shí)間片均進(jìn)行線程切換,也就是說(shuō) 1 秒可以執(zhí)行 50 個(gè)任務(wù),給人的感覺好像計(jì)算機(jī)能同時(shí)處理多件事情,其實(shí)是 CPU 執(zhí)行任務(wù)速度太快給人產(chǎn)生的錯(cuò)覺感。

3.2、實(shí)現(xiàn) Runnable 接口,然后通過(guò) Thread 類來(lái)啟動(dòng)介紹

/**
 * 實(shí)現(xiàn) Runnable 接口
 */
public class Thread2 implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date());
            System.out.println(time + " 當(dāng)前線程:" + Thread.currentThread().getName() + ",正在運(yùn)行");
        }
    }
}
/**
 * 創(chuàng)建一個(gè)測(cè)試類
 */
public class ThreadTest2 {

    public static void main(String[] args) {
        // 通過(guò)一個(gè)Thread來(lái)啟動(dòng)線程
        Thread thread2 = new Thread(new Thread2());
        thread2.start();

        for (int i = 0; i < 5; i++) {
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date());
            System.out.println(time + " 當(dāng)前線程:" + Thread.currentThread().getName() + ",正在運(yùn)行");
        }
    }
}

輸出結(jié)果:

2023-08-23 18:30:28:664 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 18:30:28:666 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 18:30:28:666 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 18:30:28:664 當(dāng)前線程:main,正在運(yùn)行
2023-08-23 18:30:28:666 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 18:30:28:667 當(dāng)前線程:Thread-0,正在運(yùn)行
2023-08-23 18:30:28:668 當(dāng)前線程:main,正在運(yùn)行
2023-08-23 18:30:28:668 當(dāng)前線程:main,正在運(yùn)行
2023-08-23 18:30:28:668 當(dāng)前線程:main,正在運(yùn)行
2023-08-23 18:30:28:668 當(dāng)前線程:main,正在運(yùn)行

效果跟上面介紹的一樣,如果循環(huán)的打印次數(shù)越多,效果越明顯!

四、線程狀態(tài)

下圖是一張從操作系統(tǒng)角度劃分的線程模型狀態(tài)!

圖片圖片

線程被分為五種狀態(tài),各個(gè)狀態(tài)說(shuō)明如下:

  • 1.新建狀態(tài):表示創(chuàng)建了一個(gè)新的線程對(duì)象,例如Thread thread = new Thread()
  • 2.就緒狀態(tài):比如調(diào)用線程的start()方法,就會(huì)處于就緒狀態(tài),也被稱為可執(zhí)行狀態(tài),隨時(shí)可能被 CPU 調(diào)度執(zhí)行
  • 3.運(yùn)行狀態(tài):獲得了 CPU 時(shí)間片,執(zhí)行程序代碼。需要注意的是,線程只能從就緒狀態(tài)進(jìn)入到運(yùn)行狀態(tài)
  • 4.阻塞狀態(tài):因?yàn)槟撤N原因出現(xiàn)了阻塞,線程放棄對(duì) CPU 的使用權(quán),停止執(zhí)行,直到阻塞事件結(jié)束,重新進(jìn)入就緒狀態(tài)才有可能再次被 CPU 調(diào)度。
  • 5.結(jié)束狀態(tài):線程里面的方法正常執(zhí)行結(jié)束或者因?yàn)槟撤N異常退出了,則該線程結(jié)束生命周期

針對(duì)操作系統(tǒng)的線程模型,Java 進(jìn)行部分封裝和擴(kuò)充,JVM 中的線程狀態(tài)總共有六種,它們之間的關(guān)系,可以用如下圖來(lái)表示:

圖片圖片

各個(gè)狀態(tài)說(shuō)明如下:

1.新建狀態(tài)(NEW):新創(chuàng)建了一個(gè)線程對(duì)象

2.運(yùn)行狀態(tài)(RUNNABLE):Java 線程中將就緒狀態(tài)和運(yùn)行中兩種狀態(tài),籠統(tǒng)的稱為“運(yùn)行”。線程對(duì)象創(chuàng)建后,調(diào)用了該對(duì)象的start()方法,該線程處于就緒狀態(tài),獲得 CPU 時(shí)間片后變?yōu)檫\(yùn)行中狀態(tài)

3.阻塞狀態(tài)(BLOCKED):因?yàn)槟撤N原因,線程放棄對(duì) CPU 的使用權(quán),停止執(zhí)行,直到進(jìn)入就緒狀態(tài)才有可能再次被 CPU 調(diào)度。比如線程在獲得synchronized同步鎖失敗后,會(huì)把線程放入鎖池中,線程進(jìn)入同步阻塞狀態(tài)。

4.等待狀態(tài)(WAITING):處于這種狀態(tài)的線程不會(huì)被分配 CPU 執(zhí)行時(shí)間,它們要等待被顯式地喚醒,否則會(huì)處于無(wú)限期等待的狀態(tài)。比如運(yùn)行狀態(tài)的線程執(zhí)行wait方法,會(huì)把線程放在等待隊(duì)列中,直到被喚醒或者因異常自動(dòng)退出

5.超時(shí)等待狀態(tài)(TIMED_WAITING):處于這種狀態(tài)的線程不會(huì)被分配 CPU 執(zhí)行時(shí)間,不過(guò)無(wú)須無(wú)限期等待被其他線程顯式地喚醒,在到達(dá)一定時(shí)間后它們會(huì)自動(dòng)喚醒。比如運(yùn)行狀態(tài)的線程執(zhí)行Thread.sleep(1000)方法,當(dāng)?shù)竭_(dá)目標(biāo)時(shí)間后,會(huì)自動(dòng)喚醒或者因異常自動(dòng)退出

6.終止?fàn)顟B(tài)(TERMINATED):表示該線程已經(jīng)執(zhí)行完畢,處于終止?fàn)顟B(tài)的線程不具備繼續(xù)運(yùn)行的能力

五、小結(jié)

本文主要圍繞進(jìn)程和線程的一些基礎(chǔ)知識(shí),進(jìn)行簡(jiǎn)單的入門知識(shí)總結(jié)。

線程的特征和進(jìn)程差不多,進(jìn)程有的它基本都有。

相對(duì)于進(jìn)程而言,線程更加的輕量化,主要承擔(dān)任務(wù)的執(zhí)行工作,優(yōu)點(diǎn)如下:

  • 一個(gè)進(jìn)程中可以同時(shí)擁有多個(gè)線程,這些線程共享該進(jìn)程的資源。我們知道進(jìn)程間的通信必須請(qǐng)求操作系統(tǒng)服務(wù)(因?yàn)?CPU 要切換到內(nèi)核態(tài)),開銷很大。而同進(jìn)程下的線程間通信,無(wú)需操作系統(tǒng)干預(yù),開銷更小
  • 線程間可以并發(fā)執(zhí)行任務(wù),線程間的并發(fā)比進(jìn)程的開銷更小,系統(tǒng)并發(fā)性更好
  • 在多 CPU 環(huán)境下,各個(gè)線程也可以分派到不同的 CPU 上并行執(zhí)行
  • 通過(guò)多線程編程,可以顯著的提升程序任務(wù)的執(zhí)行效率

不過(guò)線程也有缺點(diǎn):

  • 當(dāng)程序編程不合理,多個(gè)線程發(fā)生較長(zhǎng)時(shí)間的等待或資源競(jìng)爭(zhēng)時(shí),可能會(huì)出現(xiàn)死鎖
  • 等候使用共享資源時(shí)可能會(huì)造成程序的運(yùn)行速度變慢。這些共享資源主要是獨(dú)占性的資源,如打印機(jī)、IO 設(shè)備等

總的來(lái)說(shuō),進(jìn)程和線程各有各優(yōu)勢(shì),站在操作系統(tǒng)的設(shè)計(jì)角度而言,可以歸結(jié)為以下幾點(diǎn):

  • 采用多進(jìn)程方式,可以保證多個(gè)任務(wù)同時(shí)運(yùn)行;
  • 采用多線程方式,可以將單個(gè)任務(wù)分成不同的部分進(jìn)行執(zhí)行;
  • 提供協(xié)調(diào)機(jī)制,防止進(jìn)程之間和線程之間產(chǎn)生沖突,同時(shí)允許進(jìn)程之間和線程之間共享資源,以充分的利用系統(tǒng)資源

分享到:
標(biāo)簽:線程
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定