java 線程池第一篇 之 ThreadPoolExcutor


一:什么是線程池?

  java 線程池是將大量的線程集中管理的類,包括對線程的創建,資源的管理,線程生命周期的管理。當系統中存在大量的異步任務的時候就考慮使用java線程池管理所有的線程。減少系統資源的開銷。

二:線程池工廠類有多少種?

  java1.8 的官方文檔提供了三種線程池工廠類,每種線程池工廠類型對應不同線程管理方式(策略)。

  newCachedThreadPool(自動廢棄回收):

  當有可用的空閑線程,優先使用空閑線程,當沒有可用的空閑線程的時候就創建新的線程。空閑線程超過60s沒有被使用,將會關閉並從線程緩沖區中刪除。這種設計的好處就是當並發高峰期過了之后,大量的空閑線程就會被回收,節省系統資源。

  newFixedhreadPool(固定線程池大小):

  首先創建一個固定線程大小的線程池,將所有的線程激活,創建一個無界任務隊列存放所有的任務,當線程池中有可用的空閑線程,隊列的任務就會被消費,當線程池中沒有空閑線程,任務隊列中的任務就等待,直到有線程被空出。當某個線程應為運行期間被異常關閉,其他的線程將會接替其運行后來的任務。這種線程池的好處就是不會再高峰的時候一直創建新的線程。線程空閑的時候也不會被銷毀。除非程序員手動明確的調用關閉線程池的方法。                 

  newSingleThreadExecutor(單工作線程): 任何時候都只有一個線程被激活處理無界任務隊列,當運行中的線程因為異常而關閉的時候,新的線程將被創建,這樣的線程池將保證所有的任務順序執行。

 

三:測試線程池demo

package test.thread.threadPool;


import org.junit.Test;

import java.util.concurrent.*;

/**
* 線程池
*/
public class ThreadPool {

/**
* @version 經過測 試發現Junit的@Test注解不支持多線程,當單元測試的線程關閉之后,就會關閉所有的線程
* @see @Test 注解會調用System.exit(0); 方法退出程序異步線程無法執行
*/
public static void main(String[] args){
/*
* 創建一個線程的實例
* 核心線程大小5
* 最大線程大小10
* 線程沒有處理任務的時候存活的時間
* 創建一個數組阻塞隊列(隊列的長度為5)
* */
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,10,8000,
TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>());
for(int i=0;i<15;i++){
MyTask myTask = new MyTask(executor);
//兩種方法調用將任務加入到阻塞隊列中submit(Runnable) 和 excute(Runnable) 方法
executor.submit(myTask); //線程執行完畢返回一個future對象
}
}


}
class MyTask implements Runnable {

private ThreadPoolExecutor executor;

public MyTask(ThreadPoolExecutor ex){
this.executor=ex;
}


@Override
public void run() {
synchronized (executor) { //加鎖監視器的目的是應為多個線程修改數據,調用get方法可能獲取數不對
System.out.println("線程-" + Thread.currentThread().getId() + ":正在執行task ");
try {
//線程休眠三秒更直觀的查看效果
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("線程池中核心線程數目:" + executor.getPoolSize() + ",隊列中等待執行的任務數目:" +
executor.getQueue().size() + ",已執行完成的任務數目:" + executor.getCompletedTaskCount());
}
}
}

源碼解析:ThreadPoolExecutor 是線程池的核心類,他有四個構造函數,分別是為了選擇不同的線程工廠策略,異常處理,任務管理。

 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);  //默認線程工廠和處理器
}
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

  corePoolSzie:這個參數是線程池的核心參數,表示當前線程數小於corePoolSize的時候,線程池每接收一個新的任務將創建一個新的線程,即使有空閑的線程也不會復用。 

  maximumPooSize:最大線程池擁有的線程數,當線程池中的線程數大於corePoolSize的時候,先復用corePoolSize中的空閑線程,當沒有空閑線程的時候就創建新的線程,但是線程的總數不會超過maximunPoolSize.

  keepAliveTime:非核心線程能存活的最大時間。當線程數超過corePoolSize的時候,當有空閑的線程時間超過keepAliveTime將會被回收。

  unit:時間的單位,用TimeUnits這個類的類屬性。屬性包含NANOSECONDS,MICROSECONDS,MILLISECONDS,SECONDS,MINUTES,HOUR,DAYS

  workQueue:線程池將要消費的任務,這個任務的類型必須是線程,要繼承Runnable 的接口,就這是為什么要叫線程池,對於阻塞隊列,一般會有ArrayBlockQque,LinkedBlockQueue,synchronousQueue 三種。

  defaultHandlerExecutor:默認的拒絕策略,當線程池關閉的時候,新的任務將被拒絕,並且展現不同的處理策略

  注意:excutor.shutDown(); 方法是將線程池關閉,已經在線程池中的任務將會繼續執行,沒有被接受的任務將不會在處理。

     當線程池的隊列用的ArrayBlockQque 的時候,若線程池中的所有線程都被用完,並且還有任務進入隊里將會拋出RejectedExecutionException

四:方法解析

  ThreadExcutor 類最高繼承接口Executor,Executor 這個接口只生命了一個方法:execute(Runnable commond) 

  類uml圖

Executor 接口:execute(Runnable commond) 方法是調用線程的核心方法

ExecutorService 接口:提供了管理異步線程的方法。

    shutdown() :將當前正在執行的異步任務繼續執行,不再接受新的任務進入線程池。

    shutdownNow():將當前正執行的線程關閉,不在接受新的任務進入線程池。

    submit():將任務提交到線程池中,並且會返回Future對象。底層調用的是Runnable 的run()方法或者是callable 的call()方法

AbstractExecutorService: 實現了submit 方法,提供線程返回值,但是這種線程的執行是直接的調用的run() 方法,導致最后線程池所有的線程都是順序執行,並不是異步的

ThreadExecutor 提供了創建線程池的構造函數,以及拒絕策略,還有各種監控線程執行狀態的方法。

 

 

 

 

 

 

  

  

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM