Java多線程(5)——線程池

線程池的技術背景

在面向對象編程中,由於創建一個對象獲取內存資源或者其他更多資源,創建和銷燬對象是很費時間和資源的。在java中更是如此,虛擬機將試圖跟蹤每一個對象,以便能夠在對象銷燬後進行垃圾回收。所以提高服務效率的一種方式便是儘可能減少創建和銷燬對象的次數,特別是一些很耗資源的對象創建和銷燬。

如何利用已有對象來服務就是一個需要解決的關鍵問題,其實這就是一些“池化資源”技術產生的原因。

線程池技術如何提高服務器程序的性能

我所提到服務器程序是指能夠接受客戶請求並能處理請求的程序,而不只是指那些接受網絡客戶請求的網絡服務器程序。

多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。

線程池的簡單實現及對比測試

一般一個簡單線程池至少包含下列組成部分。

1. 線程池管理器(ThreadPollManager):用於創建並管理線程池

2. 工作線程(WorkThread):線程池中線程

3. 任務接口(Task):每個任務必須實現的接口,以供工作線程調度任務的執行

4. 任務隊列:用於存放沒有處理的任務,提供一種緩衝機制。

線程管理器:應該具有創建和管理線程的功能

下列是創建線程池的部分代碼:

private final int i=100;//Thread Pool size
private int threadNum =0;
//create threads
synchronized(workThreadVector){
	for(int j=0;j<i;j++){
			threadNum++;
			WorkThread workThread = new WorkThread(taskVector,threadNum);
			workThreadVector.addElement(workThread);
		}
}
注意同步workThreadVector並沒有降低效率,相反提高了效率。(??)Vector的相關知識可參考

下列是銷燬線程池的部分代碼:

while(!workThreadVector.isEmpty()){
		if(debugLevel > 2)
			System.out.println("stop:"+(i));
			i++;
			try{
					WorkThread workThread = (WorkThread)workThreadVector.remove(0)
					workThread.closeThread();
					continue;
				}catch(Exception ex){
						if(debugLevel > 2)
							ex.printStackTrace();
					}
					break;
	}


添加新任務的部分代碼如下:

	synchronized(taskVector){
			taskVector.addElement(taskObj);
			taskVector.notifyAll();
		}

工作線程是一個可以循環執行任務的線程,在沒有任務時將等待。

任務接口是爲所有任務提供統一的接口,以便工作線程處理。


關於高級線程池的探討

簡單線程池存在一些問題,比如如果有大量的客戶要求服務器爲其服務,但由於線程池的工作線程是有限的,服務器智能爲部分客戶服務,服務器只能爲部分客戶服務,其他客戶提交的任務,只能在任務隊列中等待處理。一些系統設計人員可能會不滿這種狀況,因爲他們對服務器程序的響應時間要求比較嚴格,所以在系統設計時可能會懷疑線程池技術的可行性,但是線程池有相應的解決方案。調整優化線程池尺寸是高線線程池要解決的一個問題。主要有下列解決方案:

方案一:動態增加工作線程

在一些高級線程池中一般提供一個可以動態改變的工作線程數目的功能,以適應突發性的請求。線程增加可以採用一種超前方式,即批量增加一批工作線程,而不是來一個請求才建立創建一個線程。批量創建時更加有效的方式。該方案還應該限制線程池中工作線程數目的上限和下限。

舉例:Jini中的TaskManager,就是一個精巧線程池管理器,它是動態增加工作線程的。SQL Server採用單進程(Single Process)多線程(Multi-Thread)的系統結構,1024個數量的線程池,動態線程分配, 理論上限32767.


方案二:優化工作線程數目

如果不想在線程池應用複雜的策略來保證工作線程數滿足應用的要求,你就要根據統計學的原理來統計客戶的請求數目,比如高峯時段平均一秒鐘內有多少任務要處理,並根據系統的承受能力及客戶的忍受能力來平衡估計一個合理的線程池尺寸。

舉例:在MTS中線程池的尺寸固定爲100.


方案三:一個服務器提供多個線程池

在一些複雜的系統結構會採用這個方案。這樣可以根據不同任務或者任務優先級來採用不同線程池處理。

舉例:COM+用到了多個線程池.


線程池技術使用範圍及應注意的問題

線程池的應用範圍:

1. 需要大量的線程來完成任務,且完成任務的時間比較短。WEB服務器完成網頁請求這樣的任務,使用線程池技術非常合適。因爲單個任務小,而任務數量巨大。

    但對於長時間的任務,比如一個Telnet連接請求,線程池的優點就不明顯了。因爲Telnet會話時間比線程的創建時間大多了。

2. 對性能要求苛刻的應用,比如要求服務器迅速相應客戶請求。

3. 接受突發性的大量請求,但不至於使服務器因此產生大量線程的應用。突發性大量客戶請求,在沒有線程池情況下,將產生大量線程,雖然理論上大部分操作系統線程數目最大值不是問題,短時間內產生大量線程可能使內存到達極限,並出現“OutOfMemory”的錯誤。


參考資料:http://www.ibm.com/developerworks/cn/java/l-threadPool/



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章