當前位置:
首頁 > 科技 > 如何設計一個實用的線程池?

如何設計一個實用的線程池?

原因排查

經過一個多小時的代碼排查終於查明了線上程序線程數過多的原因:這是一個接收MQ消息的一個服務,程序大體思路是這樣的,監聽的線程每次收到一條消息,就啟動一個線程去執行,每次啟動的線程都是新的。

說到這裡,咱們就談一談這個程序有哪些弊端:

每次收到一條消息都創建一個新的線程,要知道線程的資源對於系統來說是很昂貴的,消息處理完成還要銷毀這個線程;

這個程序用到的線程數量是沒有限制的。當線程到達一定數量,程序反而因線程在cpu切換開銷的原因處理效率降低。無論的你的伺服器cpu是多少核心,這個現象都有發生的可能。

解決問題

線程多的問題該怎麼解決呢,增加cpu核心數?治標不治本。對於開發者而言,最為常用也最為有效的是線程池化,也就是說線程池。

線程池是一種多線程處理形式,處理過程中將任務添加到隊列,然後在創建線程後自動啟動這些任務。這避免了在處理短時間任務時創建與銷毀線程的代價。線程池不僅能夠保證內核的充分利用,還能防止過分調度。可用線程數量應該取決於可用的並發處理器、處理器內核、內存、網路sockets等的數量。例如,線程數一般取cpu數量 2比較合適,線程數過多會導致額外的線程切換開銷。

線程池其中一項很重要的技術點就是任務的隊列,隊列雖然屬於一種基礎的數據結構,但是發揮了舉足輕重的作用。

隊列

隊列是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。

隊列是一種採用的FIFO(first in first out)方式的線性表,也就是經常說的先進先出策略。

實現

1、數組

隊列可以用數組Q[1…m]來存儲,數組的上界m即是隊列所容許的最大容量。在隊列的運算中需設兩個指針:head,隊頭指針,指向實際隊頭元素 1的位置;tail,隊尾指針,指向實際隊尾元素位置。一般情況下,兩個指針的初值設為0,這時隊列為空,沒有元素。以下為一個簡單的實例(生產環境需要優化):

publicclassQueueArray

{

//隊列元素的數組容器

T[] container = null;

intIndexHeader, IndexTail;

publicQueueArray(intsize)

{

container =newT[size];

IndexHeader =;

IndexTail =;

}

publicvoidEnqueue(T item)

{

//入隊的元素放在頭指針的指向位置,然後頭指針前移

container[IndexHeader] = item;

IndexHeader ;

}

publicTDequeue()

{

//出隊:把尾元素指針指向的元素取出並清空(不清空也可以)對應的位置,尾指針前移

T item = container[IndexTail];

container[IndexTail] =default(T);

IndexTail ;

returnitem;

}

}

2、鏈表

隊列採用的FIFO(first in first out),新元素總是被插入到鏈表的尾部,而讀取的時候總是從鏈表的頭部開始讀取。每次讀取一個元素,釋放一個元素。所謂的動態創建,動態釋放。因而也不存在溢出等問題。由於鏈表由元素連接而成,遍歷也方便。以下是一個實例僅供參考:

publicclassQueueLinkList

{

LinkedList contianer = null;

publicQueueLinkList()

{

contianer =newLinkedList();

}

publicvoidEnqueue(T item)

{

//入隊的元素其實就是加入到隊尾

contianer.AddLast(item);

}

publicTDequeue()

{

//出隊:取鏈表第一個元素,然後把這個元素刪除

T item = contianer.First.Value;

contianer.RemoveFirst();

returnitem;

}

}

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 CSDN 的精彩文章:

Google AI 騙過了 Google,工程師竟無計可施?
從 SAS到NVMe,換個底盤就完兒事了?

TAG:CSDN |