熟悉Java多線程編程的同窗都知道,當咱們線程建立過多時,容易引起內存溢出,所以咱們就有必要使用線程池的技術了。java
目錄數據庫
1 線程池的優點編程
2 線程池的使用數組
4 線程池的參數多線程
5 功能線程池ide
5.2 定時線程池(ScheduledThreadPool )
5.4 單線程化線程池(SingleThreadExecutor)
整體來講,線程池有以下的優點:
(1)下降資源消耗。經過重複利用已建立的線程下降線程建立和銷燬形成的消耗。
(2)提升響應速度。當任務到達時,任務能夠不須要等到線程建立就能當即執行。
(3)提升線程的可管理性。線程是稀缺資源,若是無限制的建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠進行統一的分配,調優和監控。
線程池的真正實現類是ThreadPoolExecutor,其構造方法有以下4種:
1. public ThreadPoolExecutor(int corePoolSize, 2. int maximumPoolSize, 3. long keepAliveTime, 4. TimeUnit unit, 5. BlockingQueue<Runnable> workQueue) { 6. this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 7. Executors.defaultThreadFactory(), defaultHandler); 8. } 10. public ThreadPoolExecutor(int corePoolSize, 11. int maximumPoolSize, 12. long keepAliveTime, 13. TimeUnit unit, 14. BlockingQueue<Runnable> workQueue, 15. ThreadFactory threadFactory) { 16. this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 17. threadFactory, defaultHandler); 18. } 20. public ThreadPoolExecutor(int corePoolSize, 21. int maximumPoolSize, 22. long keepAliveTime, 23. TimeUnit unit, 24. BlockingQueue<Runnable> workQueue, 25. RejectedExecutionHandler handler) { 26. this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 27. Executors.defaultThreadFactory(), handler); 28. } 30. public ThreadPoolExecutor(int corePoolSize, 31. int maximumPoolSize, 32. long keepAliveTime, 33. TimeUnit unit, 34. BlockingQueue<Runnable> workQueue, 35. ThreadFactory threadFactory, 36. RejectedExecutionHandler handler) { 37. if (corePoolSize < 0 || 38. maximumPoolSize <= 0 || 39. maximumPoolSize < corePoolSize || 40. keepAliveTime < 0) 41. throw new IllegalArgumentException(); 42. if (workQueue == null || threadFactory == null || handler == null) 43. throw new NullPointerException(); 44. this.corePoolSize = corePoolSize; 45. this.maximumPoolSize = maximumPoolSize; 46. this.workQueue = workQueue; 47. this.keepAliveTime = unit.toNanos(keepAliveTime); 48. this.threadFactory = threadFactory; 49. this.handler = handler; 50. }
能夠看到,其須要以下幾個參數:
線程池的使用流程以下:
1. // 建立線程池 2. ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, 3. MAXIMUM_POOL_SIZE, 4. KEEP_ALIVE, 5. TimeUnit.SECONDS, 6. sPoolWorkQueue, 7. sThreadFactory); 8. // 向線程池提交任務 9. threadPool.execute(new Runnable() { 10. @Override 11. public void run() { 12. ... // 線程執行的任務 13. } 14. }); 15. // 關閉線程池 16. threadPool.shutdown(); // 設置線程池的狀態爲SHUTDOWN,而後中斷全部沒有正在執行任務的線程 17. threadPool.shutdownNow(); // 設置線程池的狀態爲 STOP,而後嘗試中止全部的正在執行或暫停任務的線程,並返回等待執行任務的列表
下面來描述一下線程池工做的原理,同時對上面的參數有一個更深的瞭解。其工做原理流程圖以下:
經過上圖,相信你們已經對全部參數有個瞭解了。下面再對任務隊列、線程工廠和拒絕策略作更多的說明。
任務隊列是基於阻塞隊列實現的,即採用生產者消費者模式,在Java中須要實現BlockingQueue接口。但Java已經爲咱們提供了7種阻塞隊列的實現:
注意有界隊列和無界隊列的區別:若是使用有界隊列,當隊列飽和時並超過最大線程數時就會執行拒絕策略;而若是使用無界隊列,由於任務隊列永遠均可以添加任務,因此設置maximumPoolSize沒有任何意義。
線程工廠指定建立線程的方式,須要實現ThreadFactory接口,並實現newThread(Runnable r)方法。該參數能夠不用指定,Executors框架已經爲咱們實現了一個默認的線程工廠:
1. /** 2. * The default thread factory. 3. */ 4. private static class DefaultThreadFactory implements ThreadFactory { 5. private static final AtomicInteger poolNumber = new AtomicInteger(1); 6. private final ThreadGroup group; 7. private final AtomicInteger threadNumber = new AtomicInteger(1); 8. private final String namePrefix; 10. DefaultThreadFactory() { 11. SecurityManager s = System.getSecurityManager(); 12. group = (s != null) ? s.getThreadGroup() : 13. Thread.currentThread().getThreadGroup(); 14. namePrefix = "pool-" + 15. poolNumber.getAndIncrement() + 16. "-thread-"; 17. } 19. public Thread newThread(Runnable r) { 20. Thread t = new Thread(group, r, 21. namePrefix + threadNumber.getAndIncrement(), 22. 0); 23. if (t.isDaemon()) 24. t.setDaemon(false); 25. if (t.getPriority() != Thread.NORM_PRIORITY) 26. t.setPriority(Thread.NORM_PRIORITY); 27. return t; 28. } 29. }
當線程池的線程數達到最大線程數時,須要執行拒絕策略。拒絕策略須要實現RejectedExecutionHandler接口,並實現rejectedExecution(Runnable r, ThreadPoolExecutor executor)方法。不過Executors框架已經爲咱們實現了4種拒絕策略:
嫌上面使用線程池的方法太麻煩?其實Executors已經爲咱們封裝好了4種常見的功能線程池,以下:
建立方法的源碼:
1. public static ExecutorService newFixedThreadPool(int nThreads) { 2. return new ThreadPoolExecutor(nThreads, nThreads, 3. 0L, TimeUnit.MILLISECONDS, 4. new LinkedBlockingQueue<Runnable>()); 5. } 6. public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { 7. return new ThreadPoolExecutor(nThreads, nThreads, 8. 0L, TimeUnit.MILLISECONDS, 9. new LinkedBlockingQueue<Runnable>(), 10. threadFactory); 11. }
使用示例:
1. // 1. 建立定長線程池對象 & 設置線程池線程數量固定爲3 2. ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); 3. // 2. 建立好Runnable類線程對象 & 需執行的任務 4. Runnable task =new Runnable(){ 5. public void run() { 6. System.out.println("執行任務啦"); 7. } 8. }; 9. // 3. 向線程池提交任務 10. fixedThreadPool.execute(task);
建立方法的源碼:
1. private static final long DEFAULT_KEEPALIVE_MILLIS = 10L; 3. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { 4. return new ScheduledThreadPoolExecutor(corePoolSize); 5. } 6. public ScheduledThreadPoolExecutor(int corePoolSize) { 7. super(corePoolSize, Integer.MAX_VALUE, 8. DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, 9. new DelayedWorkQueue()); 10. } 12. public static ScheduledExecutorService newScheduledThreadPool( 13. int corePoolSize, ThreadFactory threadFactory) { 14. return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); 15. } 16. public ScheduledThreadPoolExecutor(int corePoolSize, 17. ThreadFactory threadFactory) { 18. super(corePoolSize, Integer.MAX_VALUE, 19. DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, 20. new DelayedWorkQueue(), threadFactory); 21. }
使用示例:
1. // 1. 建立 定時線程池對象 & 設置線程池線程數量固定爲5 2. ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); 3. // 2. 建立好Runnable類線程對象 & 需執行的任務 4. Runnable task =new Runnable(){ 5. public void run() { 6. System.out.println("執行任務啦"); 7. } 8. }; 9. // 3. 向線程池提交任務 10. scheduledThreadPool.schedule(task, 1, TimeUnit.SECONDS); // 延遲1s後執行任務 11. scheduledThreadPool.scheduleAtFixedRate(task,10,1000,TimeUnit.MILLISECONDS);// 延遲10ms後、每隔1000ms執行任務
建立方法的源碼:
1. public static ExecutorService newCachedThreadPool() { 2. return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 3. 60L, TimeUnit.SECONDS, 4. new SynchronousQueue<Runnable>()); 5. } 6. public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { 7. return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 8. 60L, TimeUnit.SECONDS, 9. new SynchronousQueue<Runnable>(), 10. threadFactory); 11. }
使用示例:
1. // 1. 建立可緩存線程池對象 2. ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); 3. // 2. 建立好Runnable類線程對象 & 需執行的任務 4. Runnable task =new Runnable(){ 5. public void run() { 6. System.out.println("執行任務啦"); 7. } 8. }; 9. // 3. 向線程池提交任務 10. cachedThreadPool.execute(task);
建立方法的源碼:
1. public static ExecutorService newSingleThreadExecutor() { 2. return new FinalizableDelegatedExecutorService 3. (new ThreadPoolExecutor(1, 1, 4. 0L, TimeUnit.MILLISECONDS, 5. new LinkedBlockingQueue<Runnable>())); 6. } 7. public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { 8. return new FinalizableDelegatedExecutorService 9. (new ThreadPoolExecutor(1, 1, 10. 0L, TimeUnit.MILLISECONDS, 11. new LinkedBlockingQueue<Runnable>(), 12. threadFactory)); 13. }
使用示例:
1. // 1. 建立單線程化線程池 2. ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); 3. // 2. 建立好Runnable類線程對象 & 需執行的任務 4. Runnable task =new Runnable(){ 5. public void run() { 6. System.out.println("執行任務啦"); 7. } 8. }; 9. // 3. 向線程池提交任務 10. singleThreadExecutor.execute(task);
Executors的4個功能線程池雖然方便,但如今已經不建議使用了,而是建議直接經過使用ThreadPoolExecutor的方式,這樣的處理方式讓寫的同窗更加明確線程池的運行規則,規避資源耗盡的風險。
其實Executors的4個功能線程有以下弊端: