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