一 什么是線程
在傳統(tǒng)操作系統(tǒng)中兵罢,每個進(jìn)程有一個地址空間变抽,而且默認(rèn)就有一個控制線程
線程顧名思義,就是一條流水線工作的過程束昵,一條流水線必須屬于一個車間,一個車間的工作過程是一個進(jìn)程
車間負(fù)責(zé)把資源整合到一起葛峻,是一個資源單位锹雏,而一個車間內(nèi)至少有一個流水線
流水線的工作需要電源,電源就相當(dāng)于cpu
所以泞歉,進(jìn)程只是用來把資源集中到一起(進(jìn)程只是一個資源單位逼侦,或者說資源集合),而線程才是cpu上的執(zhí)行單位腰耙。
多線程(即多個控制線程)的概念是榛丢,在一個進(jìn)程中存在多個控制線程,多個控制線程共享該進(jìn)程的地址空間挺庞,相當(dāng)于一個車間內(nèi)有多條流水線晰赞,都共用一個車間的資源。
例如,北京地鐵與上海地鐵是不同的進(jìn)程掖鱼,而北京地鐵里的13號線是一個線程然走,北京地鐵所有的線路共享北京地鐵所有的資源,比如所有的乘客可以被所有線路拉戏挡。
二 線程的創(chuàng)建開銷小
1.創(chuàng)建進(jìn)程的開銷要遠(yuǎn)大于線程芍瑞?
如果我們的軟件是一個工廠,該工廠有多條流水線褐墅,流水線工作需要電源拆檬,電源只有一個即cpu(單核cpu)
一個車間就是一個進(jìn)程,一個車間至少一條流水線(一個進(jìn)程至少一個線程)
創(chuàng)建一個進(jìn)程妥凳,就是創(chuàng)建一個車間(申請空間竟贯,在該空間內(nèi)建至少一條流水線)
而建線程,就只是在一個車間內(nèi)造一條流水線逝钥,無需申請空間屑那,所以創(chuàng)建開銷小
2.進(jìn)程之間是競爭關(guān)系,線程之間是協(xié)作關(guān)系艘款?
車間直接是競爭/搶電源的關(guān)系持际,競爭(不同的進(jìn)程直接是競爭關(guān)系,是不同的程序員寫的程序運(yùn)行的哗咆,迅雷搶占其他進(jìn)程的網(wǎng)速选酗,360把其他進(jìn)程當(dāng)做病毒干死)
一個車間的不同流水線式協(xié)同工作的關(guān)系(同一個進(jìn)程的線程之間是合作關(guān)系,是同一個程序?qū)懙某绦騼?nèi)開啟動岳枷,迅雷內(nèi)的線程是合作關(guān)系,不會自己干自己)
三 線程與進(jìn)程的區(qū)別
- Threads share the address space of the process that created it; processes have their own address space.
- Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
- Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
- New threads are easily created; new processes require duplication of the parent process.
- Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
- Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
四 為何要用多線程
多線程指的是呜叫,在一個進(jìn)程中開啟多個線程空繁,簡單的講:如果多個任務(wù)共用一塊地址空間,那么必須在一個進(jìn)程內(nèi)開啟多個線程朱庆。詳細(xì)的講分為4點(diǎn):
多線程共享一個進(jìn)程的地址空間
線程比進(jìn)程更輕量級盛泡,線程比進(jìn)程更容易創(chuàng)建可撤銷,在許多操作系統(tǒng)中娱颊,創(chuàng)建一個線程比創(chuàng)建一個進(jìn)程要快10-100倍傲诵,在有大量線程需要動態(tài)和快速修改時,這一特性很有用
若多個線程都是cpu密集型的箱硕,那么并不能獲得性能上的增強(qiáng)拴竹,但是如果存在大量的計(jì)算和大量的I/O處理,擁有多個線程允許這些活動彼此重疊運(yùn)行剧罩,從而會加快程序執(zhí)行的速度栓拜。
在多cpu系統(tǒng)中,為了最大限度的利用多核,可以開啟多個線程幕与,比開進(jìn)程開銷要小的多挑势。(這一條并不適用于python)
五 多線程的應(yīng)用舉例
開啟一個字處理軟件進(jìn)程,該進(jìn)程肯定需要辦不止一件事情啦鸣,比如監(jiān)聽鍵盤輸入潮饱,處理文字,定時自動將文字保存到硬盤诫给,這三個任務(wù)操作的都是同一塊數(shù)據(jù)香拉,因而不能用多進(jìn)程。只能在一個進(jìn)程里并發(fā)地開啟三個線程,如果是單線程蝙搔,那就只能是缕溉,鍵盤輸入時,不能處理文字和自動保存吃型,自動保存時又不能輸入和處理文字证鸥。
六 經(jīng)典的線程模型
多個線程共享同一個進(jìn)程的地址空間中的資源,是對一臺計(jì)算機(jī)上多個進(jìn)程的模擬勤晚,有時也稱線程為輕量級的進(jìn)程
而對一臺計(jì)算機(jī)上多個進(jìn)程枉层,則共享物理內(nèi)存、磁盤赐写、打印機(jī)等其他物理資源鸟蜡。
多線程的運(yùn)行也多進(jìn)程的運(yùn)行類似,是cpu在多個線程之間的快速切換挺邀。
不同的進(jìn)程之間是充滿敵意的揉忘,彼此是搶占、競爭cpu的關(guān)系端铛,如果迅雷會和QQ搶資源泣矛。而同一個進(jìn)程是由一個程序員的程序創(chuàng)建,所以同一進(jìn)程內(nèi)的線程是合作關(guān)系禾蚕,一個線程可以訪問另外一個線程的內(nèi)存地址您朽,大家都是共享的,一個線程干死了另外一個線程的內(nèi)存换淆,那純屬程序員腦子有問題哗总。
類似于進(jìn)程,每個線程也有自己的堆棧
不同于進(jìn)程倍试,線程庫無法利用時鐘中斷強(qiáng)制線程讓出CPU讯屈,可以調(diào)用thread_yield運(yùn)行線程自動放棄cpu,讓另外一個線程運(yùn)行县习。
線程通常是有益的耻煤,但是帶來了不小程序設(shè)計(jì)難度具壮,線程的問題是:
1.父進(jìn)程有多個線程,那么開啟的子線程是否需要同樣多的線程哈蝇?
如果是棺妓,那么附近某個線程被阻塞,那么copy到子進(jìn)程后炮赦,copy版的線程也要被阻塞嗎怜跑,想一想nginx的多線程模式接收用戶連接。
2.在同一個進(jìn)程中吠勘,如果一個線程關(guān)閉了問題性芬,而另外一個線程正準(zhǔn)備往該文件內(nèi)寫內(nèi)容呢?
如果一個線程注意到?jīng)]有內(nèi)存了剧防,并開始分配更多的內(nèi)存植锉,在工作一半時,發(fā)生線程切換峭拘,新的線程也發(fā)現(xiàn)內(nèi)存不夠用了俊庇,又開始分配更多的內(nèi)存,這樣內(nèi)存就被分配了多次鸡挠,這些問題都是多線程編程的典型問題辉饱,需要仔細(xì)思考和設(shè)計(jì)。
七 POSIX線程
為了實(shí)現(xiàn)可移植的線程程序,IEEE在IEEE標(biāo)準(zhǔn)1003.1c中定義了線程標(biāo)準(zhǔn)拣展,它定義的線程包叫Pthread彭沼。大部分UNIX系統(tǒng)都支持該標(biāo)準(zhǔn),簡單介紹如下
八 在用戶空間實(shí)現(xiàn)的線程
線程的實(shí)現(xiàn)可以分為兩類:用戶級線程(User-Level Thread)和內(nèi)核線線程(Kernel-Level Thread)备埃,后者又稱為內(nèi)核支持的線程或輕量級進(jìn)程姓惑。在多線程操作系統(tǒng)中,各個系統(tǒng)的實(shí)現(xiàn)方式并不相同按脚,在有的系統(tǒng)中實(shí)現(xiàn)了用戶級線程挺益,有的系統(tǒng)中實(shí)現(xiàn)了內(nèi)核級線程。
用戶級線程內(nèi)核的切換由用戶態(tài)程序自己控制內(nèi)核切換,不需要內(nèi)核干涉乘寒,少了進(jìn)出內(nèi)核態(tài)的消耗,但不能很好的利用多核Cpu,目前Linux pthread大體是這么做的匪补。
在用戶空間模擬操作系統(tǒng)對進(jìn)程的調(diào)度伞辛,來調(diào)用一個進(jìn)程中的線程,每個進(jìn)程中都會有一個運(yùn)行時系統(tǒng)夯缺,用來調(diào)度線程蚤氏。此時當(dāng)該進(jìn)程獲取cpu時,進(jìn)程內(nèi)再調(diào)度出一個線程去執(zhí)行踊兜,同一時刻只有一個線程執(zhí)行竿滨。
九 在內(nèi)核空間實(shí)現(xiàn)的線程
內(nèi)核級線程:切換由內(nèi)核控制,當(dāng)線程進(jìn)行切換的時候,由用戶態(tài)轉(zhuǎn)化為內(nèi)核態(tài)于游。切換完畢要從內(nèi)核態(tài)返回用戶態(tài)毁葱;可以很好的利用smp,即利用多核cpu贰剥。windows線程就是這樣的倾剿。
十 用戶級與內(nèi)核級線程的對比
一: 以下是用戶級線程和內(nèi)核級線程的區(qū)別:
- 內(nèi)核支持線程是OS內(nèi)核可感知的,而用戶級線程是OS內(nèi)核不可感知的蚌成。
- 用戶級線程的創(chuàng)建前痘、撤消和調(diào)度不需要OS內(nèi)核的支持,是在語言(如Java)這一級處理的担忧;而內(nèi)核支持線程的創(chuàng)建芹缔、撤消和調(diào)度都需OS內(nèi)核提供支持,而且與進(jìn)程的創(chuàng)建瓶盛、撤消和調(diào)度大體是相同的最欠。
- 用戶級線程執(zhí)行系統(tǒng)調(diào)用指令時將導(dǎo)致其所屬進(jìn)程被中斷,而內(nèi)核支持線程執(zhí)行系統(tǒng)調(diào)用指令時蓬网,只導(dǎo)致該線程被中斷窒所。
- 在只有用戶級線程的系統(tǒng)內(nèi),CPU調(diào)度還是以進(jìn)程為單位帆锋,處于運(yùn)行狀態(tài)的進(jìn)程中的多個線程吵取,由用戶程序控制線程的輪換運(yùn)行;在有內(nèi)核支持線程的系統(tǒng)內(nèi)锯厢,CPU調(diào)度則以線程為單位皮官,由OS的線程調(diào)度程序負(fù)責(zé)線程的調(diào)度。
- 用戶級線程的程序?qū)嶓w是運(yùn)行在用戶態(tài)下的程序实辑,而內(nèi)核支持線程的程序?qū)嶓w則是可以運(yùn)行在任何狀態(tài)下的程序捺氢。
二: 內(nèi)核線程的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 當(dāng)有多個處理機(jī)時,一個進(jìn)程的多個線程可以同時執(zhí)行剪撬。
缺點(diǎn):
- 由內(nèi)核進(jìn)行調(diào)度摄乒。
三: 用戶進(jìn)程的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 線程的調(diào)度不需要內(nèi)核直接參與,控制簡單残黑。
- 可以在不支持線程的操作系統(tǒng)中實(shí)現(xiàn)馍佑。
- 創(chuàng)建和銷毀線程、線程切換代價等線程管理的代價比內(nèi)核線程少得多梨水。
- 允許每個進(jìn)程定制自己的調(diào)度算法拭荤,線程管理比較靈活。
- 線程能夠利用的表空間和堆椧叻蹋空間比內(nèi)核級線程多舅世。
- 同一進(jìn)程中只能同時有一個線程在運(yùn)行旦委,如果有一個線程使用了系統(tǒng)調(diào)用而阻塞,那么整個進(jìn)程都會被掛起雏亚。另外缨硝,頁面失效也會產(chǎn)生同樣的問題。
缺點(diǎn):
- 資源調(diào)度按照進(jìn)程進(jìn)行评凝,多個處理機(jī)下追葡,同一個進(jìn)程中的線程只能在同一個處理機(jī)下分時復(fù)用
十一 混合實(shí)現(xiàn)
用戶級與內(nèi)核級的多路復(fù)用,內(nèi)核同一調(diào)度內(nèi)核線程奕短,每個內(nèi)核線程對應(yīng)n個用戶線程
最新2020整理收集的一些高頻面試題(都整理成文檔)宜肉,有很多干貨,包含mysql翎碑,netty谬返,spring,線程日杈,spring cloud遣铝、jvm、源碼莉擒、算法等詳細(xì)講解酿炸,也有詳細(xì)的學(xué)習(xí)規(guī)劃圖,面試題整理等涨冀,需要獲取這些內(nèi)容的朋友請加Q君樣:11604713672