最近在學習線程相關的知識,而後瓜熟蒂落少不了學習線程池,剛開始在沒有深刻的學習以前,感受線程池是很神祕的東西,並且徹底想不到怎麼才能實現一個本身的線程池,而後還能保證它的可用性,而後就一直琢磨,琢磨了一週才很少,也是網上各類查資料,終於明白了線程池的原理,也本身手寫一個線程池,來加深印象,那麼本文咱們就來聊一聊關於線程池的知識,但願更多的猿友能看到,今後對線程池有一個清晰直觀的認識。java
1.什麼是線程池數據庫
線程池的基本思想是一種對象池,在程序啓動時就開闢一塊內存空間,裏面存放了衆多(未死亡)的線程,池中線程執行調度由池管理器來處理。當有線程任務時,從池中取一個,執行完成後線程對象歸池,這樣能夠避免反覆建立線程對象所帶來的性能開銷,節省了系統的資源。設計模式
2.使用線程池的好處數組
合理的使用線程池能夠重複利用已建立的線程,這樣就能夠減小在建立線程和銷燬線程上花費的時間和資源。而且,線程池在某些狀況下還能動態的調整工做線程的數量,以平衡資源消耗和工做效率。同時線程池還提供了對池中工做線程進行統一的管理的相關方法。這樣就至關於咱們一次建立,就能夠屢次使用,大量的節省了系統頻繁的建立和銷燬線程所須要的資源。ide
3.線程池的主要組件性能
一個線程池包括如下四個基本組成部分:
(1)、線程池管理器(ThreadPool):用於建立並管理線程池,包括 建立線程池,銷燬線程池,添加新任務;
(2)、工做線程(WorkThread):線程池中線程,在沒有任務時處於等待狀態,能夠循環的執行任務;
(3)、任務接口(Task):每一個任務必須實現的接口,以供工做線程調度任務的執行,它主要規定了任務的入口,任務執行完後的收尾工做,任務的執行狀態等;
(4)、任務隊列(taskQueue):用於存放沒有處理的任務。提供一種緩衝機制。學習
4.JDK中線程池經常使用類UML類關係圖測試
咱們知道了線程池的原理以及主要組件以後,就讓咱們來手動實現一個本身的線程池,以加深理解和深刻學習。this
1.線程池接口類atom
package com.hafiz.proxy.threadPool; import java.util.List; /** * Desc:線程池接口類 * Created by hafiz.zhang on 2017/9/19. */ public interface ThreadPool { // 執行單個線程任務 void execute(Runnable task); // 執行多個任務 void execute(Runnable[] tasks); // 執行多個任務 void execute(List<Runnable> tasks); // 返回已經執行的任務個數 int getExecuteTaskNumber(); // 返回等待被處理的任務個數,隊列的長度 int getWaitTaskNumber(); // 返回正在工做的線程的個數 int getWorkThreadNumber(); // 關閉線程池 void destroy(); }
2.線程池實現類ThreadPoolManager.java
package com.hafiz.proxy.threadPool; import java.util.Arrays; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; /** * Desc:線程池實現類 * Created by hafiz.zhang on 2017/9/19. */ public class ThreadPoolManager implements ThreadPool { // 線程池中默認線程的個數爲5 private static Integer workerNum = 5; // 工做線程數組 WorkThread[] workThreads; // 正在執行的線程任務數量 private static volatile Integer executeTaskNumber = 0; // 任務隊列, 做爲一個緩衝 private Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<>(); // 單例模式 private static ThreadPoolManager threadPool; private AtomicLong threadNum = new AtomicLong(); private ThreadPoolManager() { this(ThreadPoolManager.workerNum); } private ThreadPoolManager(int workerNum) { if (workerNum > 0) { ThreadPoolManager.workerNum = workerNum; } workThreads = new WorkThread[ThreadPoolManager.workerNum]; for (int i = 0; i < ThreadPoolManager.workerNum; i++) { workThreads[i] = new WorkThread(); Thread thread = new Thread(workThreads[i], "ThreadPool-worker-" + threadNum.incrementAndGet()); thread.start(); System.out.println("初始化線程總數:" + (i+1) + ",當前線程名稱是:ThreadPool-worker-" + threadNum); } } public static ThreadPool getThreadPool() { return getThreadPool(workerNum); } public static ThreadPool getThreadPool(int workerNum) { if (workerNum > 0) { ThreadPoolManager.workerNum = workerNum; } if (threadPool == null) { threadPool = new ThreadPoolManager(ThreadPoolManager.workerNum); } return threadPool; } @Override public void execute(Runnable task) { synchronized (taskQueue) { taskQueue.add(task); taskQueue.notifyAll(); } } @Override public void execute(Runnable[] tasks) { execute(Arrays.asList(tasks)); } @Override public void execute(List<Runnable> tasks) { synchronized (taskQueue) { for (Runnable task : tasks) { taskQueue.add(task); } taskQueue.notifyAll(); } } @Override public String toString() { return "ThreadPoolManager{" + "當前的工做線程數量=" + getWorkThreadNumber() + ", 已完成的任務數=" + getExecuteTaskNumber() + ", 等待任務數=" + getWaitTaskNumber() + '}'; } @Override public int getExecuteTaskNumber() { return executeTaskNumber; } @Override public int getWaitTaskNumber() { return taskQueue.size(); } @Override public int getWorkThreadNumber() { return workerNum; } @Override public void destroy() { while (!taskQueue.isEmpty()) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < workThreads.length; i++) { workThreads[i].shutdown(); workThreads[i] = null; } threadPool = null; taskQueue.clear(); } private class WorkThread implements Runnable { // 線程是否可用 private boolean isRunning = true; @Override public void run() { Runnable r = null; while (isRunning) { // 隊列同步機制,加鎖 synchronized (taskQueue) { while (isRunning && taskQueue.isEmpty()) { try { taskQueue.wait(20); } catch (InterruptedException e) { e.printStackTrace(); } } if (!taskQueue.isEmpty()) { r = taskQueue.poll(); } } if (r != null) { r.run(); } executeTaskNumber++ ; r = null; } } public void shutdown() { isRunning = false; } } }
其中該類中包含內部類WorkThread,它用來包裝真正的線程類,給每個線程一個是否可用的標誌,該線程工做室同步的從taskQueue中取出要執行的任務進行調用run方法來執行任務。
這個類中的getThreadPool方法中咱們還使用到了懶漢式來實現單例,單例模式也是Java經常使用設計模式之一。
注意該類中的destroy方法的實現:咱們是一直等到隊列中的全部的任務執行完畢,才真正的銷燬線程池,銷燬的過程當中不要忘記將每個線程對象置爲null,而且清空任務隊列,這樣更利於java的垃圾回收。
3.自定義任務類Task.java
package com.hafiz.proxy.threadPool; /** * Desc:自定義任務類 * Created by hafiz.zhang on 2017/9/21. */ public class Task implements Runnable { private static volatile Integer i = 1; @Override public void run() { // 執行任務 synchronized (i) { System.out.println("當前處理的線程是:" + Thread.currentThread().getName() + ",執行任務:" + (i++) + "完成"); } } }
4.線程池測試類
package com.hafiz.proxy.threadPool; import java.util.ArrayList; import java.util.List; /** * Desc:線程池測試類 * Created by hafiz.zhang on 2017/9/20. */ public class ThreadPoolTest { public static void main(String[] args) { ThreadPool t = ThreadPoolManager.getThreadPool(6); List<Runnable> tasks = new ArrayList<>(); for (int i = 0; i < 100; i++) { tasks.add(new Task()); } System.out.println(t); t.execute(tasks); // 全部的線程執行完成才destroy t.destroy(); System.out.println(t); } }
5.測試結果:(爲了篇幅,只建立10個任務運行)
經過本文,咱們弄明白線程池究竟是怎麼工做,學習知識的過程當中,咱們就是要知其然知其因此然。這樣咱們才能更好地駕馭它,才能更好地去理解和使用,也能更好地幫助咱們舉一反三,後面有機會咱們接着來講數據庫鏈接池的原理及手寫實現。