1.并發
1.1 并發與并行
首先介紹一下并發與并行,兩者雖然隻有一字之差,但實際上卻有着本質的差別,其概念如下:
- 并行性(parallel):指在同一時刻,有多條指令在多個處理器上同時執行;
- 并發性(concurrency):指在同一時刻隻能有一條指令執行,但多個程序指令被快速輪換執行,使得在宏觀上具有多個程序同時執行的效果。

在作業系統中,安裝了多個程式,并發指的是在一段時間内宏觀上有多個程式同時運作,這在單 CPU 系統中,每一時刻隻能有一道程式執行,即微觀上這些程式是分時的交替運作,隻不過是給人的感覺是同時運作,那是因為分時交替運作的時間是非常短的。
而在多個 CPU 系統中,則這些可以并發執行的程式便可以配置設定到多個處理器上(CPU),實作多任務并行執行,即利用每個處理器來處理一個可以并發執行的程式,這樣多個程式便可以同時執行。目前電腦市場上說的多核 CPU,便是多核處理器,核越多,并行處理的程式越多,能大大的提高電腦運作的效率。
注意:單核處理器的計算機肯定是不能并行的處理多個任務的,隻能是多個任務在單個CPU上并發運作。同理,線程也是一樣的,從宏觀角度上了解線程是并行運作的,但是從微觀角度上分析卻是串行運作的,即一個線程一個線程的去運作,當系統隻有一個CPU時,線程會以某種順序執行多個線程,我們把這種情況稱之為線程排程。
1.2 順序程式設計與并發程式設計
我們在解決程式設計問題時,通常使用順序程式設計來解決,即程式中的所有事物在任意時刻都隻能執行一個步驟。然而對于某些問題,我們希望能夠并行地執行程式中的多個部分,來達到我們想要的效果。在單處理器機器中,我們可以将程式劃分為多個部分,然後每個部分由該處理器并發執行。在多處理器機器中,我們可以将程式劃分多個部分,然後每個部分分别在多個處理器上并行執行。當然為了更加充分利用CPU資源,我們也可以在多個處理器上并發執行,那麼在這我們就涉及到了另一種程式設計模式了并發程式設計。并發程式設計又叫多線程程式設計。并發程式設計使我們可以将程式劃分為多個分離的、獨立運作的任務。通過使用多線程機制,每個獨立任務都将由線程來驅動。一個線程就是在程序中的一個單一的順序控制流,單個程序可以擁有多個"并發執行"的任務。這樣使程式的每個任務,都好像擁有一個自己的CPU一樣。但其底層機制還是是切分CPU時間,CPU都有個時鐘頻率,表示每秒中能執行CPU指令的次數。在每個時鐘周期内,CPU實際上隻能去執行一條也有可能多條指令。作業系統将程序進行管理,輪流配置設定每個程序很短的一段是時間但不一定是均分,然後在每個程序内部,程式代碼自己處理該程序内部線程的時間配置設定,多個線程之間互相的切換去執行,這個切換時間也是非常短的是以通常我們不需要考慮它。
并發是指"發",不是處理,最常見的情況就是許多人在一小段時間内都點選了你的網站,發出了處理請求。并發程式設計是對并發狀況的應對,在單處理器和多處理器機器上都可對其進行應對,可這個處理方案和架構以及算法有關。CPU一般是分時的,會在極短的時間内不停地切換給不同的線程使用,無論多少并發都會處理下去,隻是時間問題,如何提高處理效率就看采用的技術了。
1.3 并發程式設計的優勢
如果使用得當,線程可以有效地降低程式的開發和維護等成本,同時提升複雜應用程式的性能。具體說,線程的優勢有:
-
發揮多處理器的強大能力
現在,多處理器系統正日益盛行,并且價格不斷降低,即時在低端伺服器和中斷桌面系統中,通常也會采用多個處理器,這種趨勢還在進一步加快,因為通過提高時鐘頻率來提升性能已變得越來越困難,處理器生産廠商都開始轉而在單個晶片上放置多個處理器核。試想,如果隻有單個線程,雙核處理器系統上程式隻能使用一半的CPU資源,擁有100個處理器的系統上将有99%的資源無法使用。多線程程式則可以同時在多個處理器上執行,如果設計正确,多線程程式可以通過提高處理器資源的使用率來提升系統吞吐率。
-
在單處理器系統上獲得更高的吞吐率
如果程式是單線程的,那麼當程式等待某個同步I/O操作完成時,處理器将處于空閑狀态。而在多線程程式中,如果一個線程在等待I/O操作完成,另一個線程可以繼續運作,使得程式能在I/O阻塞期間繼續運作。
-
模組化的簡單性
通過使用線程,可以将複雜并且異步的工作流進一步分解為一組簡單并且同步的工作流,每個工作流在一個單獨的線程中運作,并在特定的同步位置進行互動。我們可以通過一些現有架構來實作上述目标,例如Servlet和RMI,架構負責解決一些細節問題,例如請求管理、線程建立、負載平衡,并在正确的時候将請求分發給正确的應用程式元件。編寫Servlet的開發人員不需要了解多少請求在同一時刻要被處理,也不需要了解套接字的輸入流或輸出流是否被阻塞,當調用Servlet的service方法來響應Web請求時,可以以同步的方式來處理這個請求,就好像它是一個單線程程式。
-
異步事件的簡化處理
伺服器應用程式在接受多個來自遠端用戶端的套接字連接配接請求時,如果為每個連接配接都配置設定其各自的線程并且使用同步I/O,那麼就會降低這類程式的開發難度。如果某個應用程式對套接字執行讀操作而此時還沒有資料到來,那麼這個讀操作将一直阻塞,直到有資料到達。在單線程應用程式中,這不僅意味着在處理請求的過程中将停頓,而且還意味着在這個線程被阻塞期間,對所有請求的處理都将停頓。為了避免這個問題,單線程伺服器應用程式必須使用非阻塞I/O,但是這種I/O的複雜性要遠遠高于同步I/O,并且很容易出錯。然而,如果每個請求都擁有自己的處理線程,那麼在處理某個請求時發生的阻塞将不會影響其他請求的處理。
在實際應用中,多線程是非常有用的,一個浏覽器必須能同時下載下傳多個圖檔;一個Web伺服器必須能同時響應多個使用者請求;Java虛拟機本身就在背景提供了一個超級線程來進行垃圾回收;圖形使用者界面(GUI)應用也需要啟動單獨的線程從主機環境收集使用者界面事件……總之,多線程在實際程式設計中的應用是非常廣泛的。
-
2.程序和線程
- 程序:是指一個記憶體中運作的應用程式,每個程序都有一個獨立的記憶體空間,一個應用程式可以同時運作多個程序;程序也是程式的一次執行過程,是系統運作程式的基本機關;系統運作一個程式即是一個程序從建立、運作到消亡的過程。程序可以了解為受作業系統管理的基本運作單元。360浏覽器是一個程序、WPS也是一個程序,正在作業系統中運作的".exe"都可以了解為一個程序。
-
線程:線程是程序中的一個執行單元,負責目前程序中程式的執行,一個程序中至少有一個線程。一個程序中是可以有多個線程的,這個應用程式也可以稱之為多線程程式。
程序中獨立運作的子任務就是一個線程。像QQ.exe運作的時候就有很多子任務在運作,比如聊天線程、好友視訊線程、下載下傳檔案線程等等。
簡而言之:一個程式運作後至少有一個程序,一個程序中可以包含多個線程。并發程式設計專題(一)-并發與多線程 3.多任務、多程序、多線程
幾乎所有的作業系統都支援同時運作多個任務,一個任務通常就是一個程式,每個運作中的程式就是一個程序。當一個程式運作時,内部可能包含了多個順序執行流,每個順序執行流就是一個線程。3.1 多程序
實作并發最直接的方式是在作業系統級别使用程序,程序是運作在它自己的位址空間内的自包容的程式。多任務作業系統可以通過周期性地将CPU從一個程序切換到另一個程序,來實作同時運作多個程序。 盡管對于一個CPU而言,它在某個時間點隻能運作一個程序,但CPU可以在多個程序之間進行輪換執行,并且CPU的切換速度極高,使我們無法感覺其切換的過程,就好像有多個程序在同時執行。
幾乎所有的作業系統都支援程序的概念,所有運作中的任務通常對應一個程序(Process)。當一個程式進入記憶體運作時,即變成一個程序。程序是處于運作過程中的程式,并且具有一定的獨立功能,程序是系統進行資源配置設定和排程的一個獨立機關。一般而言,程序包含如下3個特征。
■ 獨立性:程序是系統中獨立存在的實體,它可以擁有自己獨立的資源,每一個程序都擁有自己私有的位址空間。在沒有經過程序本身允許的情況下,一個使用者程序不可以直接通路其他程序的位址空間。
■ 動态性:程序與程式的差別在于,程式隻是一個靜态的指令集合,而程序是一個正在系統中活動的指令集合。在程序中加入了時間的概念,程序具有自己的生命周期和各種不同的狀态,這些概念在程式中部是不具備的。
■ 并發性:多個程序可以在單個處理器上并發執行,多個程序之間不會互相影響。
3.2 多線程
3.2.1 多線程概述
多線程則擴充了多程序的概念。使得同一個程序中也可以同時并發處理多個任務。線程(Thread)也被稱作輕量級程序(Lightweight Process)。線程是程序的執行單元,就像程序在作業系統中的地位一樣,線程在程式中是獨立的、并發的執行流。當程序被初始化後,主線程就被建立了。對于絕大多數的應用程式來說,通常僅要求有一個主線程,但也可以在該程序内建立多條順序執行流,這些順序執行流就是線程,每個線程也是互相獨立的。
線程是程序的組成部分,一個程序可以擁有多個線程,一個線程必須有一個父程序。線程可以擁有自己的堆棧、自己的程式計數器和自己的局部變量,但不擁有系統資源,它與父程序的其他線程共享該程序所擁有的全部資源。因為多個線程共享父程序裡的全部資源,是以程式設計更加友善;但必須更加小心,我們必須確定線程不會妨礙同一程序裡的其他線程。
3.2.2 多線程機制
線程模型為程式設計帶來了便利,它簡化了在單一程式中同時交織在一起的多個操作的處理。在使用線程時,CPU将輪流給每個任務配置設定其占用時間。每個任務都覺得自己在一直占用CPU,但事實上CPU時間是劃分成片段配置設定給了所有的任務。線程的一大好處是可以使你從這個層次抽身出來,即代碼不必知道它是運作在具有一個還是多個CPU的機器上。是以,使用線程機制是一種建立透明的、可擴充的程式的方法,如果程式行得太慢,為機器增添一個CPU就能很容易地加快程式的運作速度。多任務和多線程往往是使用多處理器系統的最合理方式。