在面向對象程式設計中,建立和銷毀對象是很費時間的,因為建立一個對象要擷取記憶體資源或者其它更多資源。在java中更是如此,虛拟機将試圖跟蹤每一個對象,以便能夠在對象銷毀後進行垃圾回收。是以提高服務程式效率的一個手段就是盡可能減少建立和銷毀對象的次數,特别是一些很耗資源的對象建立和銷毀。如何利用已有對象來服務就是一個需要解決的關鍵問題,其實這就是一些"池化資源"技術産生的原因。比如大家所熟悉的資料庫連接配接池正是遵循這一思想而産生的,本文将介紹的線程池技術同樣符合這一思想。
諸如web伺服器、資料庫伺服器、檔案伺服器和郵件伺服器等許多伺服器應用程式都需要處理一種常見的情況:單個任務處理的時間很短而請求的數目卻是巨大的。假設我們建構一個簡單伺服器應用程式模型:每當一個請求到達就建立一個新的服務對象,然後在新的服務對象中為請求服務。伺服器程式利用線程技術響應客戶請求已經司空見慣,可能您認為這樣做效率已經很高,但是當我們遇到大量的客戶并發地通路應用伺服器時采用這種伺服器模型會有很多問題。我們采用線程池技術來解決這種單個任務處理時問很短而請求數目卻是巨大的這樣的難題。
目前,一些著名的大公司都特别看好這項技術,并早已經在他們的産品中應用該技術。比如ibm的websphere,iona的orbix 2000在sun的jini中,microsoft的mts(microsofttransaction server 2.0),com+等。
在應用伺服器中需要處理從用戶端發起的任務請求,這些任務往往具有高密度、短時間的特性。無論通過什麼方式在伺服器得到用戶端請求後,伺服器都需要獨立地處理這個客戶請求。針對這個問題,線程池提供了處理系統性能和大使用者量請求之間的沖突的方法。通過對多個任務重用已經存在的線程對象,降低了對線程對象建立和銷毀的開銷。當客戶請求時,線程對象已經存在,可以提高請求的響應時間,進而整體地提高了系統服務的表現。
多線程技術主要解決處理器單元内多個線程執行的問題,它可以使處理器盡量保持忙碌狀态,充分利用系統的可用資源,使得系統的性能得到顯著提高。但是如果對多線程技術應用不當的話,也會事與願違,可以通過一個簡單的例子來說明這一點。
線程執行過程分為三個部分:t1、t2、t3。其中t1表示線程建立的時間,t2表示線程執行任務所需時間,包括線程間同步所需時間,t3表示線程銷毀時間。那麼我們可以看出,執行任務所需時間t為t1+t2+t3,然而真正處理任務的時間為t2,線程本身的開銷為t1、t3兩部分之和,這樣線程開銷占總時間的比例為(t1+t3)/(t1+t2+t3)。如果任務處理的時間t2比較短小,那建立和銷毀的開銷所占的比例将會非常大,因而如何減少t1和t3兩部分時間是需要解決的問題。線程池正是着眼于減少t1和t3這兩部分時間的開銷,使得系統的效率提高。他把t1和t3分别安排在伺服器程式啟動和結束的時間段或者一些空閑的時間段,這樣在伺服器程式處理客戶請求時就不會t1和t3開銷了。
線程池技術有着如下幾個方面的優點:
(1)可以控制産生線程的數量。通過預先建立一定數量的工作線程并限制其數量,控制線程對象的記憶體消耗。
(2)降低系統開銷和資源消耗。通過對多個請求重用線程、線程建立、銷毀的開銷被分攤到了多個請求上。另外就是通過限制線程數量、降低系統在垃圾回收方面的開銷。
(3)提高系統響應速度。線程事先已被建立,請求到達時可直接進行處理,消除了因線程建立所帶來的時間延遲,另外多個線程可以并發處理。
(4)java線程池的程式設計模型相對于原有的多線程程式設計模型來說,還有一大改進,那就是線程代碼和業務代碼的分離。
一般來說實作一個線程池主要包括以下幾個組成部分:
(1)線程管理器:用于建立并管理線程池。
(2)工作線程:線程池中實際執行任務的線程。在初始化線程時會預先建立好固定數目的線程在池中,這些初始化的線程一般是處于空閑狀态,不消耗cpu,占用較小的記憶體空間。
(3)任務接口:每個任務必須實作的接口,當線程池中的可執行的任務時,被工作線程調試執行。把任務抽象出來形成任務接口,可以做到線程池與具體的任務無關。
(4)任務隊列:用來存放沒有處理的任務,提供一種緩沖機制。實作這種結構有好幾種方法,常用的是隊列,主要是利用它先進先出的工作原理;另外一種是連結清單之類的資料結構,可以動态為它配置設定記憶體空間,應用中比較靈活。我們用到的是連結清單資料結構形式來實作任務隊列。