在傳統服務器結構中, 常是 有一個總的 監聽線程監聽有沒有新的用戶鏈接服務器, 每當有一個新的 用戶進入, 服務器就開啓一個新的線程用戶處理這 個用戶的數據包。這個線程只服務於這個用戶 , 當 用戶與服務器端關閉鏈接之後, 服務器端銷燬這個線程。然而頻繁地開闢與銷燬線程極大地佔用了系統的資源。並且在大量用戶的狀況下, 系統爲了開闢和銷燬線程將浪費大量的時間和資源。線程池提供了一個解決外部大量用戶與服務器有限資源的矛盾, 線程池和傳統的一個用戶對應一個線程的處理方法不一樣, 它的基本思想就是在程序 開始時就在內存中開闢一些線程, 線程的數目是 固定的,他們獨自造成一個類, 屏蔽了對外的操做, 而服務器只須要將數據包交給線程池就能夠了。當有新的客戶請求到達時 , 不是新建立一個線程爲其服務 , 而是從「池子」中選擇一個空閒的線程爲新的客戶請求服務 ,服務完畢後 , 線程進入空閒線程池中。若是沒有線程空閒 的 話, 就 將 數據 包 暫 時 積 累 , 等 待 線 程 池 內 有 線 程空閒之後再進行處理。經過對多個任務重用已經存在的線程對象 , 下降了對線程對象建立和銷燬的開銷。當客戶請求 時 , 線程對象 已 經 存 在 , 可 以 提 高 請 求 的響應時間 , 從而總體地提升了系統服務的表現。
通常來講實現一個線程池主要包括如下幾個組成部分:
1)線程管理器:用於建立並管理線程池。
2)工做線程:線程池中實際執行任務的線程。在初始化線程時會預先建立好固定數目的線程在池中,這些初始化的線程通常處於空閒狀態,通常不佔用CPU,佔用較小的內存空間。
3)任務接口:每一個任務必須實現的接口,當線程池的任務隊列中有可執行任務時,被空閒的工做線程調去執行(線程的閒與忙是經過互斥量實現的,跟前面文章中的設置標誌位差很少),把任務抽象出來造成接口,能夠作到線程池與具體的任務無關。
4)任務隊列:用來存放沒有處理的任務,提供一種緩衝機制,實現這種結構有好幾種方法,經常使用的是隊列,主要運用先進先出原理,另一種是鏈表之類的數據結構,能夠動態的爲它分配內存空間,應用中比較靈活,下文中就是用到的鏈表。
下面的不在贅述百度《線程池技術在併發服務器中的應用》寫的很是詳細! 服務器
何時須要建立線程池呢?簡單的說,若是一個應用須要頻繁的建立和銷燬線程,而任務執行的時間又很是短,這樣線程建立和銷燬的帶來的開銷就不容忽視,這時也是線程池該出場的機會了。若是線程建立和銷燬時間相比任務執行時間能夠忽略不計,則沒有必要使用線程池了。 網絡
大多數的網絡服務器,包括Web服務器都具備一個特色,就是單位時間內必須處理數目巨大的鏈接請求,可是處理時間倒是比較短的。在傳統的多線程服務器模型中是這樣實現的:一旦有個請求到達,就建立一個新的線程,由該線程執行任務,任務執行完畢以後,線程就退出。這就是"即時建立,即時銷燬"的策略。儘管與建立進程相比,建立線程的時間已經大大的縮短,可是若是提交給線程的任務是執行時間較短,並且執行次數很是頻繁,那麼服務器就將處於一個不停的建立線程和銷燬線程的狀態。這筆開銷是不可忽略的,尤爲是線程執行的時間很是很是短的狀況。 數據結構
線程池就是爲了解決上述問題的,它的實現原理是這樣的:在應用程序啓動以後,就立刻建立必定數量的線程,放入空閒的隊列中。這些線程都是處於阻塞狀態,這些線程只佔一點內存,不佔用CPU。當任務到來後,線程池將選擇一個空閒的線程,將任務傳入此線程中運行。當全部的線程都處在處理任務的時候,線程池將自動建立必定的數量的新線程,用於處理更多的任務。執行任務完成以後線程並不退出,而是繼續在線程池中等待下一次任務。當大部分線程處於阻塞狀態時,線程池將自動銷燬一部分的線程,回收系統資源。 多線程
下面是一個簡單線程池的實現,這個線程池的代碼是我參考網上的一個例子實現的,因爲找不到出處了,就沒辦法註明參考自哪裏了。它的方案是這樣的:程序啓動以前,初始化線程池,啓動線程池中的線程,因爲尚未任務到來,線程池中的全部線程都處在阻塞狀態,當一有任務到達就從線程池中取出一個空閒線程處理,若是全部的線程都處於工做狀態,就添加到隊列,進行排隊。若是隊列中的任務個數大於隊列的所能容納的最大數量,那就不能添加任務到隊列中,只能等待隊列不滿才能添加任務到隊列中。 併發