您好,登錄后才能下訂單哦!
本篇文章為大家展示了java中怎么實現(xiàn)一個線程池,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
有些人可能對線程池比較陌生,并且更不熟悉線程池的工作原理。所以他們在使用線程的時候,多數(shù)情況下都是new Thread來實現(xiàn)多線程。但是,往往良好的多線程設(shè)計大多都是使用線程池來實現(xiàn)的。 為什么要使用線程 降低資源的消耗。降低線程創(chuàng)建和銷毀的資源消耗。提高響應(yīng)速度:線程的創(chuàng)建時間為T1,執(zhí)行時間T2,銷毀時間T3,免去T1和T3的時間提高線程的可管理性
下圖所示為線程池的實現(xiàn)原理:調(diào)用方不斷向線程池中提交任務(wù);線程池中有一組線程,不斷地從隊列中取任務(wù),這是一個典型的生產(chǎn)者-消費者模型。
要實現(xiàn)一個線程池,有幾個問題需要考慮:
隊列設(shè)置多長?如果是無界的,調(diào)用方不斷往隊列中方任務(wù),可能導(dǎo)致內(nèi)存耗盡。如果是有界的,當(dāng)隊列滿了之后,調(diào)用方如何處理?
線程池中的線程個數(shù)是固定的,還是動態(tài)變化的?
每次提交新任務(wù),是放入隊列?還是開新線程
當(dāng)沒有任務(wù)的時候,線程是睡眠一小段時間?還是進入阻塞?如果進入阻塞,如何喚醒?
針對問題4,有3種做法:
不使用阻塞隊列,只使用一般的線程安全的隊列,也無阻塞/喚醒機制。當(dāng)隊列為空時,線程池中的線程只能睡眠一會兒,然后醒來去看隊列中有沒有新任務(wù)到來,如此不斷輪詢。
不使用阻塞隊列,但在隊列外部,線程池內(nèi)部實現(xiàn)了阻塞/喚醒機制
使用阻塞隊列
很顯然,做法3最完善,既避免了線程池內(nèi)部自己實現(xiàn)阻塞/喚醒機制的麻煩,也避免了做法1的睡眠/輪詢帶來的資源消耗和延遲。
現(xiàn)在來帶大家手寫一個簡單的線程池,讓大家更加理解線程池的工作原理
根據(jù)上圖可以知道,實現(xiàn)線程池需要一個阻塞隊列+存放線程的容器
/** * Five在努力 * 自定義線程池 */ public class ThreadPool { /** 默認線程池中的線程的數(shù)量 */ private static final int WORK_NUM = 5; /** 默認處理任務(wù)的數(shù)量 */ private static final int TASK_NUM = 100; /** 存放任務(wù) */ private final BlockingQueue<Runnable> taskQueue; private final Set<WorkThread> workThreads;//保存線程的集合 private int workNumber;//線程數(shù)量 private int taskNumber;//任務(wù)數(shù)量 public ThreadPool(){ this(WORK_NUM , TASK_NUM); } public ThreadPool(int workNumber , int taskNumber) { if (taskNumber<=0){ taskNumber = TASK_NUM; } if (workNumber<=0){ workNumber = WORK_NUM; } this.taskQueue = new ArrayBlockingQueue<Runnable>(taskNumber); this.workNumber = workNumber; this.taskNumber = taskNumber; workThreads = new HashSet<>(); //工作線程準(zhǔn)備好了 //啟動一定數(shù)量的線程數(shù),從隊列中獲取任務(wù)處理 for (int i=0;i<workNumber;i++) { WorkThread workThread = new WorkThread("thead_"+i); workThread.start(); workThreads.add(workThread); } } /** * 線程池執(zhí)行任務(wù)的方法,其實就是往BlockingQueue中添加元素 * @param task */ public void execute(Runnable task) { try { taskQueue.put(task); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 銷毀線程池 */ public void destroy(){ System.out.println("ready close pool..."); for (WorkThread workThread : workThreads) { workThread.stopWorker(); workThread = null;//help gc } workThreads.clear(); } /** 內(nèi)部類,工作線程的實現(xiàn) */ private class WorkThread extends Thread{ public WorkThread(String name){ super(); setName(name); } @Override public void run() { while (!interrupted()) { try { Runnable runnable = taskQueue.take();//獲取任務(wù) if (runnable !=null) { System.out.println(getName()+" ready execute:"+runnable.toString()); runnable.run();//執(zhí)行任務(wù) } runnable = null;//help gc } catch (Exception e) { interrupt(); e.printStackTrace(); } } } public void stopWorker(){ interrupt(); } } }
上面代碼定義了默認的線程數(shù)量和默認處理任務(wù)數(shù)量,同時用戶也可以自定義線程數(shù)量和處理任務(wù)數(shù)量。用BlockingQueue阻塞隊列來存放任務(wù)。用set來存放工作線程,set的好處就不用多說了。懂的都懂
構(gòu)造方法中new對象的時候,循環(huán)啟動線程,并把線程放入set中。WorkThread實現(xiàn)Thread,run方法實現(xiàn)也很簡單,因為有一個stop方法,所以這里需要while判斷,之后從taskQueue隊列中,獲取任務(wù)。如何獲取不到就阻塞,獲取到的話runnable.run();就執(zhí)行任務(wù),之后把任務(wù)變成null
銷毀線程只需要遍歷set,把每個線程停止,并且變?yōu)閚ull就行了
執(zhí)行線程任務(wù)execute,只需要從往阻塞隊列中添加任務(wù)就行了
測試一下:
public class TestMySelfThreadPool { private static final int TASK_NUM = 50;//任務(wù)的個數(shù) public static void main(String[] args) { ThreadPool myPool = new ThreadPool(3,50); for (int i=0;i<TASK_NUM;i++) { myPool.execute(new MyTask("task_"+i)); } } static class MyTask implements Runnable{ private String name; public MyTask(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("task :"+name+" end..."); } @Override public String toString() { // TODO Auto-generated method stub return "name = "+name; } } }
上述內(nèi)容就是java中怎么實現(xiàn)一個線程池,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。