六、線程
6.1 線程的引入
引入理由
- 應用的需要
- 開銷的考慮
- 性能的考慮
6.1.1 應用的需要
我們看一個例子,一個
web
伺服器的工作方式
- 從用戶端接收網頁請求
- 從磁盤上檢索相關的網頁,讀入記憶體(此時程序是停止的,直到讀取完畢)
- 将網頁傳回給對應的用戶端
可以看到每次從磁盤讀取的時候程序都是暫停的,這樣會導緻性能低下
那如何提高伺服器的工作效率?通常情況下是使用網頁緩存
在
沒有線程情況下的兩種解決方案
- 一個服務程序undefined這種情況下也是一種順序程式設計,雖然采用了緩存機制,但是性能同樣不高。而如果設定多個程序,這多個程序之間又是互相獨立的,有獨立的位址空間,是以不能共享資訊
- 有限狀态機undefined這種方式程式設計模型複雜,采用非阻塞的
I/O
多線程的解決方式

**說明:**這是一個多線程的
web
伺服器的工作方式,首先讀取用戶端的請求,之後由分派線程将各個任務分派給工作線程,這裡還是采用了網頁緩存
于是我們可以看到一個
web
伺服器的實作有三種方式:
6.1.2 開銷的考慮
6.1.3 性能的考慮
如果有多個處理器的話,一個程序就會有多個線程同時在執行了,這樣可以極大的提高運作性能
6.2 線程的基本概念
線程的屬性
- 有辨別符
ID
- 有狀态及狀态轉換
需要提供一些操作-->
- 不運作時需要儲存的上下文(程式計數器等寄存器)
- 有自己的棧和棧指針
- 共享所在程序的位址空間和其他資源
- 建立、撤銷另一個線程(程式開始是以一個單線程方式運作的)
6.3 線程機制的實作
一般有三種實作機制
- 使用者級線程
- 核心級線程
- 混合(兩者結合)方法6.3.1 使用者級線程
說明:線程是由運作時系統管理的,在核心中隻有程序表。典型例子就是
UNIX
undefinedPOSIX線程庫–PTHREAD
優點
- 線程切換快
- 排程算法是應用程式特定的
- 使用者級線程可運作在任何作業系統上(隻需要實作線程庫)
缺點
- 核心隻将處理器配置設定給程序,同一程序中的兩個線程不能同時運作于兩個處理器上
- 大多數系統調用是阻塞的,是以,由于核心阻塞程序,故程序中所有線程也被阻塞。(可以在調用之前判斷進行解決,如果是阻塞線程,那麼就換其他線程)6.3.2 核心級線程
- 線程建立在使用者空間完成
- 線程排程等在核心态完成
- 例子如
作業系統Solaris
6.4 線程狀态(Java)
0)建立:建立後尚未啟動的線程處于這種狀态。
1)運作:包括了 OS 中 Running 和 Ready 狀态,也就是處于此狀态的線程可能正在運作,也可能正在等待 cpu 為它配置設定執行時間
2)無限期等待:處于這種狀态的線程不會被配置設定 cpu 執行時間,要等待其他線程顯示喚醒。以下方法會讓線程進入無限期等待 :
- 沒有設定 timeout 的 object.wait()
- 沒有設定 timeout 參數的 Thread.join()
- LockSupport.park()
3)有限期的等待:處于這種狀态的線程也不會被配置設定 cpu 執行時間,不過無需等待被其他線程顯示喚醒,而是在一定時間後,他們會由 OS 自動喚醒 1.設定了 timeout 的 object.wait() 方法 2. 設定了 timeout 參數的 Thread.join() 3.LockSupport.parkNanos()
4.LockSupport.parkUnit()
4) 阻塞:與"等待"的差別:
- 阻塞态在等待擷取一個排它鎖,這個事件将在另外一個線程放棄這個鎖的時候發生
- 等待狀态在等待一段時間或者喚醒動作。
5)結束:已終止線程的線程狀态,線程已經結束執行。 程序的通信類型
- 共享存儲器、管道、客戶機-伺服器系統(socket)
- 直接通信、間接通信(信箱)