Java多線程專題之線程與進(jìn)程概述
前言
大家好,一直以來我都本著用最通俗的話理解核心的知識點, 我認(rèn)為所有的難點都離不開 「基礎(chǔ)知識」 的鋪墊。目前正在出一個Java多線程專題長期系列教程,從入門到進(jìn)階, 篇幅會較多, 喜歡的話,給個關(guān)注?? ~
適合人群
- 有一定的Java基礎(chǔ)。
- 想學(xué)習(xí)或了解多線程開發(fā)。
- 想提高自己的同學(xué)。
背景
之前給大家講了一些框架的使用,這些都屬于業(yè)務(wù)層面的東西,你需要熟練掌握它并在項目中會運用它即可,但這些對自身技術(shù)的積累是遠(yuǎn)遠(yuǎn)不夠的,如果你想要提高自己,對于語言本身你需要花更多的時間去挖掘而不是局限于框架的使用,所以之前為什么跟大家一直強(qiáng)調(diào)基礎(chǔ)的重要性,框架可以千變?nèi)f化,層出不窮,但是基礎(chǔ)它是不變的,不管是學(xué)java還是前端或者是其它語言, 這一點大家還是需要認(rèn)清的。
接下來的幾期會專門講多線程這一塊,篇幅會較多,耐心看完你一定會有收獲~
情景回顧
之前有給大家講過Java的基礎(chǔ)和進(jìn)階部分,如果這方面還薄弱的同學(xué),可以到底部查看往期教程。那時本來想把多線程也出一些教程,但是可能對于大家會有點難度,特別是剛?cè)腴T的同學(xué),而且這方面的知識又比較多?;蛟S平時項目開發(fā),只是用用框架或者直接使用框架提供的一些多線程方法,很少會自己手寫,即便這樣,還是需要深入學(xué)習(xí)的,因為面試的時候,這個地方幾乎是必問的,而且對于自身的提高還是有幫助的。
今天我們不涉及代碼部分,先帶著大家過一遍理論,一起來看一下什么是線程和進(jìn)程 ~
什么是進(jìn)程
在講之前,先給大家講一下,在早期,計算機(jī)是如何工作的。
在很早以前,計算機(jī)都是通過一個個指令去工作的,用戶輸入一個指令,計算機(jī)完成一個操作,這種效率是很低的。因為輸入一個指令,計算機(jī)就等待。后來人們引入了批量處理,將一系列指令交給計算機(jī)處理,但是這個過程仍然是串行的,內(nèi)部執(zhí)行還是會阻塞。隨著時間的發(fā)展,人們對于計算機(jī)的性能要求越來越高,因為時間就是金錢,如果能提高效率,老板當(dāng)然高興了~
后來,人們就提出了計算機(jī)進(jìn)程的概念, 我們先看一下百科中是如何描述進(jìn)程的:
進(jìn)程(Process)是計算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運行活動,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。在早期面向進(jìn)程設(shè)計的計算機(jī)結(jié)構(gòu)中,進(jìn)程是程序的基本執(zhí)行實體
這里,仍然不給大家提線程的概念,我們接著看進(jìn)程。我們從中可以得到一個核心點,它是計算機(jī)系統(tǒng)資源分配和調(diào)度的基本單位。那么它又是怎么去分配和調(diào)度的呢?
上下文切換
當(dāng)程序通過某種手段(編程語言編寫)被編譯為一系列指令和數(shù)據(jù)集合后,此時,CPU采用時間片輪轉(zhuǎn)的方式運行進(jìn)程。CPU為每個進(jìn)程分配一個時間段,稱作它的時間片。如果在時間片結(jié)束時進(jìn)程還在運行,則暫停這個進(jìn)程的運行,并且CPU分配給另一個進(jìn)程(這個過程叫做上下文切換)。如果進(jìn)程在時間片結(jié)束前阻塞或結(jié)束,則CPU立即進(jìn)行切換,不用等待時間片用完。
當(dāng)進(jìn)程暫停時,它會保存當(dāng)前進(jìn)程的狀態(tài)(進(jìn)程標(biāo)識,進(jìn)程使用的資源等),在下一次切換回來時根據(jù)之前保存的狀態(tài)進(jìn)行恢復(fù),接著繼續(xù)執(zhí)行。
使用進(jìn)程和CPU時間片輪轉(zhuǎn)方式,在宏觀上看起來同一時間段執(zhí)行多個任務(wù),但在事實上,對于單核CPU來說,任意具體時刻都只有一個任務(wù)在占用CPU資源。
隨著時間的推移,人們覺得這種方式還是有點效率低,不能夠滿足日常需求了。下面就是我們要講的線程的概念了
什么是線程
我們知道進(jìn)程在某一時刻只能處理一件事情,如果要處理其它的,只能等待前面的任務(wù)完成。于是呢,人們就提出了線程的概念。之前講進(jìn)程的概念的時候,其實還有一句話:
在當(dāng)代面向線程設(shè)計的計算機(jī)結(jié)構(gòu)中,進(jìn)程是線程的容器。程序是指令、數(shù)據(jù)及其組織形式的描述,進(jìn)程是程序的實體。
從中可知,線程是存于進(jìn)程之中,一個進(jìn)程可以有多個線程,一個線程可以處理一個子任務(wù),它是并發(fā)程序的基礎(chǔ)。有的人可能問了,我多進(jìn)程處理不也可以嗎?使用多線程有什么優(yōu)勢?
首先我們需要知道的是處理一個程序不單單是執(zhí)行任務(wù),完了就結(jié)束了,往往我們的執(zhí)行的任務(wù)之間是互相依賴的,也就是說任務(wù)之間需要交互,在這里叫進(jìn)程通信或者線程通信。下面我們就說說這兩者的比較
進(jìn)程通信 & 線程通信
首先我們要知道進(jìn)程和線程的本質(zhì)區(qū)別,線程是進(jìn)程的子集,一個進(jìn)程可以有多個線程。從運行環(huán)境上可以得知,進(jìn)程是獨立的運行環(huán)境, 線程是進(jìn)程下分配的一個子任務(wù),也就是說進(jìn)程獨占系統(tǒng)資源和內(nèi)存空間。這樣一想,如果開啟多個進(jìn)程是比較消耗系統(tǒng)資源的。進(jìn)程的創(chuàng)建和銷毀不僅需要保存寄存器和棧信息,還需要資源的分配回收以及調(diào)度,開銷較大。線程只需要保存寄存器和棧信息,開銷較小,所以這也是使用線程的優(yōu)勢。
進(jìn)程與進(jìn)程之間是互相隔離的,一個進(jìn)程出現(xiàn)問題不會影響其它進(jìn)程的運行,而線程崩潰是有可能影響整個程序的。另外一個重要區(qū)別是,進(jìn)程是操作系統(tǒng)進(jìn)行資源分配的基本單位,而線程是操作系統(tǒng)進(jìn)行調(diào)度的基本單位,即CPU分配時間的單位。
上下文切換過程
這個概念非常重要,大家一定要好好去理解~
寄存器
上面提到寄存器,那么它是啥呢?它和上下文切換脫不開關(guān)系。上下文切換是指 CPU 從一個進(jìn)程(或線程)切換到另一個進(jìn)程(或線程)。上下文是指某一時間點CPU寄存器和程序計數(shù)器的內(nèi)容
寄存器是cpu內(nèi)部的少量的速度很快的閃存,通常存儲和訪問計算過程的中間值提高計算機(jī)程序的運行速度。
程序計數(shù)器
程序計數(shù)器是一個專用的寄存器,用于表明指令序列中CPU,正在執(zhí)行的位置,存的值為正在執(zhí)行的指令的位置或者下一個將要被執(zhí)行的指令的位置,具體實現(xiàn)依賴于特定的系統(tǒng)。
說的有點抽象,給大家舉個例子。這里開啟了兩個線程A,B。那么線程A怎么切到B的呢?
- 首先A線程掛起, 并將當(dāng)前在cpu中的狀態(tài)保存到內(nèi)存中。
- 在內(nèi)存中檢索下一個線程B的上下文并將其在CPU的寄存器中恢復(fù),執(zhí)行B線程。
- 當(dāng)B執(zhí)行完,根據(jù)程序計數(shù)器中指向的位置恢復(fù)線程A。
過程分析
CPU通過為每個線程分配CPU時間片來實現(xiàn)多線程機(jī)制,CPU通過時間片分配算法來循環(huán)執(zhí)行任務(wù),當(dāng)前任務(wù)執(zhí)行一個時間片后會切換到下一個任務(wù)。但是,在切換前會保存上一個任務(wù)的狀態(tài),以便下次切換回這個任務(wù)時,可以再加載這個任務(wù)的狀態(tài),所以任務(wù)從保存到再加載的過程就是一次上下文切換。
??上下文切換通常是計算密集型的,意味著此操作會消耗大量的CPU時間, 如果你面試被問到Redis為什么采用單線程I/O多路復(fù)用模型,這個地方是不是可以拿出來講一講呢?
結(jié)束語
本期到這里就結(jié)束了, 總結(jié)一下,本節(jié)主要講了什么是線程,什么是進(jìn)程,以及上下文切換的概念。這些概念性的東西,大家不要去背,要自己去理解,不懂的地方可以自己再去搜索,一定要理解,然后自己多總結(jié)總結(jié)~