Java之線程池簡(jiǎn)單實(shí)現(xiàn)
以前做的東西,實(shí)現(xiàn)一個(gè)簡(jiǎn)單的多線程機(jī)制,開(kāi)始之前,現(xiàn)說(shuō)說(shuō)原理性的東西吧,下面是我在ibm開(kāi)發(fā)者上搜到的內(nèi)容
線程池的技術(shù)背景
在面向?qū)ο缶幊讨校瑒?chuàng)建和銷毀對(duì)象是很費(fèi)時(shí)間的,因?yàn)閯?chuàng)建一個(gè)對(duì)象要獲取內(nèi)存資源或者其它更多資源。在Java中更是如此,虛擬機(jī)將試圖跟蹤每一個(gè)對(duì)象, 以便能夠在對(duì)象銷毀后進(jìn)行垃圾回收。所以提高服務(wù)程序效率的一個(gè)手段就是盡可能減少創(chuàng)建和銷毀對(duì)象的次數(shù),特別是一些很耗資源的對(duì)象創(chuàng)建和銷毀。如何利用 已有對(duì)象來(lái)服務(wù)就是一個(gè)需要解決的關(guān)鍵問(wèn)題,其實(shí)這就是一些"池化資源"技術(shù)產(chǎn)生的原因。
多線程技術(shù)主要解決處理器單元內(nèi)多個(gè)線程執(zhí)行的問(wèn)題,它可以顯著減少處理器單元的閑置時(shí)間,增加處理器單元的吞吐能力。但如果對(duì)多線程應(yīng)用不當(dāng),會(huì)增加對(duì)單個(gè)任務(wù)的處理時(shí)間。可以舉一個(gè)簡(jiǎn)單的例子:
假設(shè)在一臺(tái)服務(wù)器完成一項(xiàng)任務(wù)的時(shí)間為T
◆ T1 創(chuàng)建線程的時(shí)間
◆ T2 在線程中執(zhí)行任務(wù)的時(shí)間,包括線程間同步所需時(shí)間
◆ T3 線程銷毀的時(shí)間
顯然T = T1+T2+T3。注意這是一個(gè)極度簡(jiǎn)化的假設(shè)。
可以看出T1,T3是多線程本身的帶來(lái)的開(kāi)銷,我們渴望減少T1,T3所用的時(shí)間,從而減少T的時(shí)間。但一些線程的使用者并沒(méi)有注意到 這一點(diǎn),所以在程序中頻繁的創(chuàng)建或銷毀線程,這導(dǎo)致T1和T3在T中占有相當(dāng)比例。顯然這是突出了線程的弱點(diǎn)(T1,T3),而不是優(yōu)點(diǎn)(并發(fā)性)。
線程池技術(shù)正是關(guān)注如何縮短或調(diào)整T1,T3時(shí)間的技術(shù),從而提高服務(wù)器程序性能的。它把T1,T3分別安排在服務(wù)器程序的啟動(dòng)和結(jié)束的時(shí)間段或者一些空閑的時(shí)間段,這樣在服務(wù)器程序處理客戶請(qǐng)求時(shí),不會(huì)有T1,T3的開(kāi)銷了。
線程池不僅調(diào)整T1,T3產(chǎn)生的時(shí)間段,而且它還顯著減少了創(chuàng)建線程的數(shù)目。在看一個(gè)例子:
假設(shè)一個(gè)服務(wù)器一天要處理50000個(gè)請(qǐng)求,并且每個(gè)請(qǐng)求需要一個(gè)單獨(dú)的線程完成。我們比較利用線程池技術(shù)和不利于線程池技術(shù)的服務(wù)器 處理這些請(qǐng)求時(shí)所產(chǎn)生的線程總數(shù)。在線程池中,線程數(shù)一般是固定的,所以產(chǎn)生線程總數(shù)不會(huì)超過(guò)線程池中線程的數(shù)目或者上限(以下簡(jiǎn)稱線程池尺寸),而如果 服務(wù)器不利用線程池來(lái)處理這些請(qǐng)求則線程總數(shù)為50000。一般線程池尺寸是遠(yuǎn)小于50000。所以利用線程池的服務(wù)器程序不會(huì)為了創(chuàng)建50000而在處 理請(qǐng)求時(shí)浪費(fèi)時(shí)間,從而提高效率。
這些都是假設(shè),不能充分說(shuō)明問(wèn)題,下面我將討論線程池的簡(jiǎn)單實(shí)現(xiàn)并對(duì)該程序進(jìn)行對(duì)比測(cè)試,以說(shuō)明線程技術(shù)優(yōu)點(diǎn)及應(yīng)用領(lǐng)域。
一般一個(gè)簡(jiǎn)單線程池至少包含下列組成部分
◆ 線程池管理器(ThreadPoolManager):用于創(chuàng)建并管理線程池
◆ 工作線程(WorkThread): 線程池中線程
◆ 任務(wù)接口(Task):每個(gè)任務(wù)必須實(shí)現(xiàn)的接口,以供工作線程調(diào)度任務(wù)的執(zhí)行。
◆ 任務(wù)隊(duì)列:用于存放沒(méi)有處理的任務(wù)。提供一種緩沖機(jī)制。
線程池管理器至少有下列功能:創(chuàng)建線程池,銷毀線程池,添加新任務(wù)。下面就是小弟的實(shí)現(xiàn),還是歡迎拍磚哈:
- public class ThreadPoolManager {
- private static ThreadPoolManager instance = null;
- private List<Upload> taskQueue = Collections.synchronizedList(new LinkedList<Upload>());//任務(wù)隊(duì)列
- private WorkThread[] workQueue ; //工作線程(真正執(zhí)行任務(wù)的線程)
- private static int worker_num = 5; //工作線程數(shù)量(默認(rèn)工作線程數(shù)量是5)
- private static int worker_count = 0;
- private ThreadPoolManager(){
- this(5);
- }
- private ThreadPoolManager(int num){
- worker_num = num;
- workQueue = new WorkThread[worker_num];
- for(int i=0;i<worker_num;i++){
- workQueue[i] = new WorkThread(i);
- }
- }
- public static synchronized ThreadPoolManager getInstance(){
- if(instance==null)
- instance = new ThreadPoolManager();
- return instance;
- }
- public void addTask(Upload task){
- //對(duì)任務(wù)隊(duì)列的操作要上鎖
- synchronized (taskQueue) {
- if(task!=null){
- taskQueue.add(task);
- taskQueue.notifyAll();
- System.out.println("task id "+task.getInfo() + " submit!");
- }
- }
- }
- public void BatchAddTask(Upload[] tasks){
- //對(duì)任務(wù)隊(duì)列的修改操作要上鎖
- synchronized (taskQueue) {
- for(Upload e:tasks){
- if(e!=null){
- taskQueue.add(e);
- taskQueue.notifyAll();
- System.out.println("task id "+e.getInfo() + " submit!");
- }
- }
- }
- }
- public void destory(){
- System.out.println("pool begins to destory ...");
- for(int i = 0;i<worker_num;i++){
- workQueue[i].stopThread();
- workQueue[i] = null;
- }
- //對(duì)任務(wù)隊(duì)列的操作要上鎖
- synchronized (taskQueue) {
- taskQueue.clear();
- }
- System.out.println("pool ends to destory ...");
- }
- private class WorkThread extends Thread{
- private int taksId ;
- private boolean isRuning = true;
- private boolean isWaiting = false;
- public WorkThread(int taskId){
- this.taksId= taskId;
- this.start();
- }
- public boolean isWaiting(){
- return isWaiting;
- }
- // 如果任務(wù)進(jìn)行中時(shí),不能立刻終止線程,需要等待任務(wù)完成之后檢測(cè)到isRuning為false的時(shí)候,退出run()方法
- public void stopThread(){
- isRuning = false;
- }
- @Override
- public void run() {
- while(isRuning){
- Upload temp = null;
- //對(duì)任務(wù)隊(duì)列的操作要上鎖
- synchronized (taskQueue) {
- //任務(wù)隊(duì)列為空,等待新的任務(wù)加入
- while(isRuning&&taskQueue.isEmpty()){
- try {
- taskQueue.wait(20);
- } catch (InterruptedException e) {
- System.out.println("InterruptedException occre...");
- e.printStackTrace();
- }
- }
- if(isRuning)
- temp = taskQueue.remove(0);
- }
- //當(dāng)?shù)却氯蝿?wù)加入時(shí)候,終止線程(調(diào)用stopThread函數(shù))造成 temp = null
- if(temp!=null){
- System.out.println("task info: "+temp.getInfo()+ " is begining");
- isWaiting = false;
- temp.uploadPic();
- isWaiting = true;
- System.out.println("task info: "+temp.getInfo()+ " is finished");
- }
- }
- }
- }
- }
然后定義任務(wù)接口(Task):這里我定義的是上傳圖片的功能接口(這里用抽象類或者接口隨你自己)。
- public abstract class Upload {
- protected String info;
- abstract boolean uploadPic();
- public String getInfo(){
- return info;
- }
- }
然后定義具體任務(wù)類:我這里簡(jiǎn)單,讓它睡眠2s。當(dāng)然你也可以定義很多實(shí)現(xiàn)Upload的任務(wù)類。
- public class TaskUpload extends Upload {
- public TaskUpload(String info){
- this.info = info;
- }
- public String getInfo(){
- return info;
- }
- @Override
- public boolean uploadPic() {
- // TODO Auto-generated method stub
- System.out.println(info+"sleep begin ....");
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println(info+"sleep end ....");
- return false;
- }
- }
***,測(cè)試這個(gè)簡(jiǎn)單的線程池:
- public class ThreadPoolManagerTest {
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Upload[] tasks = createBatchTask(7);
- ThreadPoolManager pool = ThreadPoolManager.getInstance();
- pool.BatchAddTask(tasks);
- pool.destory();
- }
- private static Upload[] createBatchTask(int n){
- Upload[] tasks = new TaskUpload[n];
- for(int i = 0;i<n ;i++ ){
- tasks[i] = new TaskUpload("task id is "+ i);
- }
- return tasks;
- }
- }
線程池技術(shù)適用范圍及應(yīng)注意的問(wèn)題
線程池的應(yīng)用范圍:
1、需要大量的線程來(lái)完成任務(wù),且完成任務(wù)的時(shí)間比較短。 WEB服務(wù)器完成網(wǎng)頁(yè)請(qǐng)求這樣的任務(wù),使用線程池技術(shù)是非常合適的。因?yàn)閱蝹€(gè)任務(wù)小,而任務(wù)數(shù)量巨大,你可以想象一個(gè)熱門網(wǎng)站的點(diǎn)擊次數(shù)。 但對(duì)于長(zhǎng)時(shí)間的任務(wù),比如一個(gè)Telnet連接請(qǐng)求,線程池的優(yōu)點(diǎn)就不明顯了。因?yàn)門elnet會(huì)話時(shí)間比線程的創(chuàng)建時(shí)間大多了。
2、對(duì)性能要求苛刻的應(yīng)用,比如要求服務(wù)器迅速相應(yīng)客戶請(qǐng)求。
3、接受突發(fā)性的大量請(qǐng)求,但不至于使服務(wù)器因此產(chǎn)生大量線程的應(yīng)用。突發(fā)性大量客戶請(qǐng)求,在沒(méi)有線程池情況下,將產(chǎn)生大量線程,雖然理論上大部分操作系統(tǒng)線程數(shù)目***值不是問(wèn)題,短時(shí)間內(nèi)產(chǎn)生大量線程可能使內(nèi)存到達(dá)極限,并出現(xiàn)"OutOfMemory"的錯(cuò)誤。
原文鏈接:http://www.cnblogs.com/slider/archive/2012/01/16/2323895.html
【編輯推薦】