Java代碼構(gòu)建一個(gè)線程池_第1頁
Java代碼構(gòu)建一個(gè)線程池_第2頁
Java代碼構(gòu)建一個(gè)線程池_第3頁
Java代碼構(gòu)建一個(gè)線程池_第4頁
Java代碼構(gòu)建一個(gè)線程池_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、在現(xiàn)代的操作系統(tǒng)中, 有一個(gè)很重要的概念 線程,幾乎所有目前流行的操作系統(tǒng)都 支持線程, 線程來源于操作系統(tǒng)中進(jìn)程的概念, 進(jìn)程有自己的虛擬地址空間以及正文段、 數(shù)據(jù)段及堆棧,而且各自占有不同的系統(tǒng)資源(例如文件、環(huán)境變量等等 。與此不同, 線程不能單獨(dú)存在, 它依附于進(jìn)程, 只能由進(jìn)程派生。 如果一個(gè)進(jìn)程派生出了兩個(gè)線程, 那這兩個(gè)線程共享此進(jìn)程的全局變量和代碼段,但每個(gè)線程各擁有各自的堆棧,因此它 們擁有各自的局部變量, 線程在 UNIX 系統(tǒng)中還被進(jìn)一步分為用戶級(jí)線程 (由進(jìn)程自已 來管理和系統(tǒng)級(jí)線程(由操作系統(tǒng)的調(diào)度程序來管理 。既然有了進(jìn)程, 為什么還要提出線程的概念呢?因?yàn)榕c創(chuàng)建一

2、個(gè)新的進(jìn)程相比,創(chuàng) 建一個(gè)線程將會(huì)耗費(fèi)小得多的系統(tǒng)資源,對(duì)于一些小型的應(yīng)用,可能感覺不到這點(diǎn),但 對(duì)于那些并發(fā)進(jìn)程數(shù)特別多的應(yīng)用,使用線程會(huì)比使用進(jìn)程獲得更好的性能,從而降低 操作系統(tǒng)的負(fù)擔(dān)。另外,線程共享創(chuàng)建它的進(jìn)程的全局變量,因此線程間的通訊編程會(huì) 更將簡(jiǎn)單, 完全可以拋棄傳統(tǒng)的進(jìn)程間通訊的 IPC 編程, 而采用共享全局變量來進(jìn)行線 程間通訊。有了上面這個(gè)概念, 我們下面就進(jìn)入正題,來看一下線程池究竟是怎么一回事?其 實(shí)線程池的原理很簡(jiǎn)單,類似于操作系統(tǒng)中的緩沖區(qū)的概念,它的流程如下:先啟動(dòng)若 干數(shù)量的線程,并讓這些線程都處于睡眠狀態(tài),當(dāng)客戶端有一個(gè)新請(qǐng)求時(shí),就會(huì)喚醒線 程池中的某一個(gè)睡

3、眠線程,讓它來處理客戶端的這個(gè)請(qǐng)求,當(dāng)處理完這個(gè)請(qǐng)求后,線程 又處于睡眠狀態(tài)??赡苣阋苍S會(huì)問:為什么要搞得這么麻煩,如果每當(dāng)客戶端有新的請(qǐng) 求時(shí), 我就創(chuàng)建一個(gè)新的線程不就完了?這也許是個(gè)不錯(cuò)的方法,因?yàn)樗苁沟媚憔帉?代碼相對(duì)容易一些,但你卻忽略了一個(gè)重要的問題 性能!就拿我所在的單位來說, 我的單位是一個(gè)省級(jí)數(shù)據(jù)大集中的銀行網(wǎng)絡(luò)中心, 高峰期每秒的客戶端請(qǐng)求并發(fā)數(shù)超過 100,如果為每個(gè)客戶端請(qǐng)求創(chuàng)建一個(gè)新線程的話,那耗費(fèi)的 CPU 時(shí)間和內(nèi)存將是驚人 的,如果采用一個(gè)擁有 200個(gè)線程的線程池,那將會(huì)節(jié)約大量的的系統(tǒng)資源,使得更多 的 CPU 時(shí)間和內(nèi)存用來處理實(shí)際的商業(yè)應(yīng)用,而不是頻繁

4、的線程創(chuàng)建與銷毀。既然一切都明白了, 那我們就開始著手實(shí)現(xiàn)一個(gè)真正的線程池吧, 線程編程可以有 多種語言來實(shí)現(xiàn),例如 C 、 C +、 java 等等,但不同的操作系統(tǒng)提供不同的線程 API 接口, 為了讓你能更明白線程池的原理而避免陷入煩瑣的 API 調(diào)用之中, 我采用了 JA V A 語言來實(shí)現(xiàn)它,由于 JA V A 語言是一種跨平臺(tái)的語言,因此你不必為使用不同的操作系 統(tǒng)而無法編譯運(yùn)行本程序而苦惱,只要你安裝了 JDK1.2以上的版本,都能正確地編譯 運(yùn)行本程序。另外 JA V A 語言本身就內(nèi)置了線程對(duì)象,而且 JA V A 語言是完全面像對(duì)象 的,因此能夠讓你更清晰地了解線程池的原理

5、,如果你注意看一下本文的標(biāo)題,你會(huì)發(fā) 現(xiàn)整個(gè)示例程序的代碼只有大約 100行。本示例程序由三個(gè)類構(gòu)成,第一個(gè)是 TestThreadPool 類,它是一個(gè)測(cè)試程序,用來 模擬客戶端的請(qǐng)求,當(dāng)你運(yùn)行它時(shí),系統(tǒng)首先會(huì)顯示線程池的初始化信息,然后提示你 從鍵盤上輸入字符串,并按下回車鍵,這時(shí)你會(huì)發(fā)現(xiàn)屏幕上顯示信息,告訴你某個(gè)線程 正在處理你的請(qǐng)求, 如果你快速地輸入一行行字符串,那么你會(huì)發(fā)現(xiàn)線程池中不斷有線 程被喚醒,來處理你的請(qǐng)求,在本例中,我創(chuàng)建了一個(gè)擁有 10個(gè)線程的線程池,如果 線程池中沒有可用線程了,系統(tǒng)會(huì)提示你相應(yīng)的警告信息,但如果你稍等片刻,那你會(huì) 發(fā)現(xiàn)屏幕上會(huì)陸陸續(xù)續(xù)提示有線程進(jìn)入了

6、睡眠狀態(tài),這時(shí)你又可以發(fā)送新的請(qǐng)求了。第二個(gè)類是 ThreadPoolManager 類,顧名思義,它是一個(gè)用于管理線程池的類,它 的主要職責(zé)是初始化線程池, 并為客戶端的請(qǐng)求分配不同的線程來進(jìn)行處理,如果線程 池滿了,它會(huì)對(duì)你發(fā)出警告信息。最后一個(gè)類是 SimpleThread 類,它是 Thread 類的一個(gè)子類,它才真正對(duì)客戶端的 請(qǐng)求進(jìn)行處理, SimpleThread 在示例程序初始化時(shí)都處于睡眠狀態(tài),但如果它接受到了 ThreadPoolManager 類發(fā)過來的調(diào)度信息,則會(huì)將自己?jiǎn)拘?并對(duì)請(qǐng)求進(jìn)行處理。 首先我們來看一下 TestThreadPool 類的源碼:/TestThr

7、eadPool.java234 public class TestThreadPool5 6 public static void main(String args7 8 try9 BufferedReader br = new BufferedReader(new InputStreamReader(System.in;10 String s;11 ThreadPoolManager manager = new ThreadPoolManager(10;12 while(s = br.readLine( != null13 14 cess(s;15 16 catch(I

8、OException e17 18 由于此測(cè)試程序用到了輸入輸入類,因此第 1行導(dǎo)入了 JA V A 的基本 IO 處理包, 在第 11行中, 我們創(chuàng)建了一個(gè)名為 manager 的類, 它給 ThreadPoolManager 類的構(gòu)造函 數(shù)傳遞了一個(gè)值為 10的參數(shù), 告訴 ThreadPoolManager 類:我要一個(gè)有 10個(gè)線程的池, 給我創(chuàng)建一個(gè)吧!第 12行至 15行是一個(gè)無限循環(huán),它用來等待用戶的鍵入,并將鍵入 的字符串保存在 s 變量中, 并調(diào)用 ThreadPoolManager 類的 process 方法來將這個(gè)請(qǐng)求進(jìn) 行處理。下面我們?cè)龠M(jìn)一步跟蹤到 ThreadPoo

9、lManager 類中去,以下是它的源代碼:/ThreadPoolManager.java234 class ThreadPoolManager5 67 private int maxThread;8 public Vector vector;9 public void setMaxThread(int threadCount10 11 maxThread = threadCount;12 1314 public ThreadPoolManager(int threadCount15 16 setMaxThread(threadCount;18 vector = new Vector(;19

10、for(int i = 1; i <= 10; i+20 21 SimpleThread thread = new SimpleThread(i;22 vector.addElement(thread;23 thread.start(;24 25 2627 public void process(String argument28 29 int i;30 for(i = 0; i < vector.size(; i+31 32 SimpleThread currentThread = (SimpleThreadvector.elementAt(i; 33 if(!currentTh

11、read.isRunning(34 36 currentThread.setArgument(argument;37 currentThread.setRunning(true;38 return;39 40 41 if(i = vector.size(42 44 45 46 /end of class ThreadPoolManager我們先關(guān)注一下這個(gè)類的構(gòu)造函數(shù),然后再看它的 process(方法。第 16-24行是 它的構(gòu)造函數(shù), 首先它給 ThreadPoolManager 類的成員變量 maxThread 賦值, maxThread 表示用于控制線程池中最大線程的數(shù)量。 第 18行

12、初始化一個(gè)數(shù)組 vector , 它用來存放所 有的 SimpleThread 類,這時(shí)候就充分體現(xiàn)了 JA V A 語言的優(yōu)越性與藝術(shù)性:如果你用 C 語言的話, 至少要寫 100行以上的代碼來完成 vector 的功能, 而且 C 語言數(shù)組只能容納 類型統(tǒng)一的基本數(shù)據(jù)類型,無法容納對(duì)象。好了,閑話少說,第 19-24行的循環(huán)完成 這樣一個(gè)功能:先創(chuàng)建一個(gè)新的 SimpleThread 類,然后將它放入 vector 中去,最后用 thread.start(來啟動(dòng)這個(gè)線程,為什么要用 start(方法來啟動(dòng)線程呢?因?yàn)檫@是 JA V A 語 言中所規(guī)定的,如果你不用的話,那這些線程將永遠(yuǎn)得不

13、到激活,從而導(dǎo)致本示例程序 根本無法運(yùn)行。下面我們?cè)賮砜匆幌?process(方法, 第 30-40行的循環(huán)依次從 vector 數(shù)組中選取 SimpleThread 線程,并檢查它是否處于激活狀態(tài)(所謂激活狀態(tài)是指此線程是否正在處 理客戶端的請(qǐng)求 , 如果處于激活狀態(tài)的話, 那繼續(xù)查找 vector 數(shù)組的下一項(xiàng), 如果 vector 數(shù)組中所有的線程都處于激活狀態(tài)的話,那它會(huì)打印出一條信息,提示用戶稍候再試。 相反如果找到了一個(gè)睡眠線程的話,那第 35-38行會(huì)對(duì)此進(jìn)行處理,它先告訴客戶端 是哪一個(gè)線程來處理這個(gè)請(qǐng)求,然后將客戶端的請(qǐng)求,即字符串 argument 轉(zhuǎn)發(fā)給 SimpleTh

14、read 類的 setArgument(方法進(jìn)行處理,并調(diào)用 SimpleThread 類的 setRunning(方法來喚醒當(dāng)前線程,來對(duì)客戶端請(qǐng)求進(jìn)行處理??赡苣氵€對(duì) setRunning(方法是怎樣喚醒線程的有些不明白,那我們現(xiàn)在就進(jìn)入最 后一個(gè)類:SimpleThread 類,它的源代碼如下:/SimpleThread.java1 class SimpleThread extends Thread2 3 private boolean runningFlag;4 private String argument;5 public boolean isRunning(6 7 return

15、runningFlag;8 9 public synchronized void setRunning(boolean flag10 11 runningFlag = flag;12 if(flag13 this.notify(;14 1516 public String getArgument(17 18 return this.argument;19 20 public void setArgument(String string21 22 argument = string;23 2425 public SimpleThread(int threadNumber26 27 running

16、Flag = false;29 3031 public synchronized void run(32 33 try34 while(true35 36 if(!runningFlag37 38 this.wait(;39 40 else41 43 sleep(5000;45 setRunning(false;46 47 48 catch(InterruptedException e50 51 /end of run(52 /end of class SimpleThread如果你對(duì) JA V A 的線程編程有些不太明白的話,那我先在這里簡(jiǎn)單地講解一下, JA V A 有一個(gè)名為 Threa

17、d 的類,如果你要?jiǎng)?chuàng)建一個(gè)線程,則必須要從 Thread 類中繼承, 并且還要實(shí)現(xiàn) Thread 類的 run(接口, 要激活一個(gè)線程, 必須調(diào)用它的 start(方法, start(方法會(huì)自動(dòng)調(diào)用 run(接口,因此用戶必須在 run(接口中寫入自己的應(yīng)用處理邏輯。那 么我們?cè)趺磥砜刂凭€程的睡眠與喚醒呢?其實(shí)很簡(jiǎn)單, JA V A 語言為所有的對(duì)象都內(nèi)置 了 wait(和 notify(方法,當(dāng)一個(gè)線程調(diào)用 wait(方法時(shí),則線程進(jìn)入睡眠狀態(tài),就像停 在了當(dāng)前代碼上了,也不會(huì)繼續(xù)執(zhí)行它以下的代碼了,當(dāng)調(diào)用 notify(方法時(shí),則會(huì)從 調(diào)用 wait(方法的那行代碼繼續(xù)執(zhí)行以下的代碼,這個(gè)

18、過程有點(diǎn)像編譯器中的斷點(diǎn)調(diào)試 的概念。 以本程序?yàn)槔? 第 38行調(diào)用了 wait(方法, 則這個(gè)線程就像凝固了一樣停在了38 行上了,如果我們?cè)诘?13 行進(jìn)行一個(gè) notify(調(diào)用的話,那線程會(huì)從第 38 行上喚醒, 繼續(xù)從第 39 行開始執(zhí)行以下的代碼了。 通過以上的講述, 我們現(xiàn)在就不難理解 SimpleThread 類了, 914 行通過設(shè)置一 第 個(gè)標(biāo)志 runningFlag 激活當(dāng)前線程,第 2529 行是 SimpleThread 類的構(gòu)造函數(shù),它用來 告訴客戶端啟動(dòng)的是第幾號(hào)進(jìn)程。第 3150 行則是我實(shí)現(xiàn)的 run(接口,它實(shí)際上是一 個(gè)無限循環(huán),在循環(huán)中首先判斷一下標(biāo)志 runningFlag,如果沒有 runningFlag 為 false 的 話,那線程處理睡眠狀態(tài),否則第 4245 行會(huì)進(jìn)行真正的處理:先打印用戶鍵入的字 符串,然后睡眠 5 秒鐘,為什么要睡眠 5 秒鐘呢?如果你不加上這句代碼的話,由于計(jì) 算機(jī)處理速度遠(yuǎn)遠(yuǎn)超過你的鍵盤輸入速度, 因此你看到的總是第 1 號(hào)線程來處理你的請(qǐng) 求,從而達(dá)不到演示效果。最后第 45 行調(diào)用 setRunning(方法又將線程置于睡眠狀態(tài), 等待新請(qǐng)求的到來。 最后還有一點(diǎn)要注意的是,如果你在一個(gè)方法中調(diào)用了 wait(和 notify(函數(shù),那你

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論