Java線程池Executor使用
阿新 • • 發佈:2018-03-23
Java.並發編程引言
合理利用線程池能夠帶來三個好處。第一:降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。第二:減少系統對於,外部 服務的響應時間的等待。第三:提高線程的可管理性。線程是稀缺資源,如果無限制的創建,那麽系統內存就會消耗完,所以就用引用到線程池的概念。
線程池主要就了解一個方法就可以了
了解幾個參數
corePoolSize(線程池的基本大小):當提交一個任務到線程池時,線程池會創建一個線程來執行任務,即使其他空閑的基本線程能夠執行新任務也會創建線程,等到需要執行的任務數大於線程池基本大小時就不再創建。如果調用了線程池的prestartAllCoreThreads方法,線程池會提前創建並啟動所有基本線程。
runnableTaskQueue(任務隊列):用於保存等待執行的任務的阻塞隊列。可以選擇以下幾個阻塞隊列。
ArrayBlockingQueue:是一個基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。
LinkedBlockingQueue:一個基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個隊列。
SynchronousQueue:一個不存儲元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個隊列。
PriorityBlockingQueue:一個具有優先級得無限阻塞隊列。
maximumPoolSize(線程池最大大小):線程池允許創建的最大線程數。如果隊列滿了,並且已創建的線程數小於最大線程數,則線程池會再創建新的線程執行任務。值得註意的是如果使用了無界的任務隊列這個參數就沒什麽效果。
ThreadFactory:用於設置創建線程的工廠,可以通過線程工廠給每個創建出來的線程設置更有意義的名字,Debug和定位問題時非常又幫助。
RejectedExecutionHandler(飽和策略):當隊列和線程池都滿了,說明線程池處於飽和狀態,那麽必須采取一種策略處理提交的新任務。這個策略默認情況下是AbortPolicy,表示無法處理新任務時拋出異常。以下是JDK1.5提供的四種策略。n AbortPolicy:直接拋出異常。
合理利用線程池能夠帶來三個好處。第一:降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。第二:減少系統對於,外部 服務的響應時間的等待。第三:提高線程的可管理性。線程是稀缺資源,如果無限制的創建,那麽系統內存就會消耗完,所以就用引用到線程池的概念。
線程池主要就了解一個方法就可以了
了解幾個參數
corePoolSize(線程池的基本大小):當提交一個任務到線程池時,線程池會創建一個線程來執行任務,即使其他空閑的基本線程能夠執行新任務也會創建線程,等到需要執行的任務數大於線程池基本大小時就不再創建。如果調用了線程池的prestartAllCoreThreads方法,線程池會提前創建並啟動所有基本線程。
ArrayBlockingQueue:是一個基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。
LinkedBlockingQueue:一個基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個隊列。
SynchronousQueue:一個不存儲元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個隊列。
maximumPoolSize(線程池最大大小):線程池允許創建的最大線程數。如果隊列滿了,並且已創建的線程數小於最大線程數,則線程池會再創建新的線程執行任務。值得註意的是如果使用了無界的任務隊列這個參數就沒什麽效果。
ThreadFactory:用於設置創建線程的工廠,可以通過線程工廠給每個創建出來的線程設置更有意義的名字,Debug和定位問題時非常又幫助。
RejectedExecutionHandler(飽和策略):當隊列和線程池都滿了,說明線程池處於飽和狀態,那麽必須采取一種策略處理提交的新任務。這個策略默認情況下是AbortPolicy,表示無法處理新任務時拋出異常。以下是JDK1.5提供的四種策略。n AbortPolicy:直接拋出異常。
CallerRunsPolicy:只用調用者所在線程來運行任務。
DiscardOldestPolicy:丟棄隊列裏最近的一個任務,並執行當前任務。
DiscardPolicy:不處理,丟棄掉。
當然也可以根據應用場景需要來實現RejectedExecutionHandler接口自定義策略。如記錄日誌或持久化不能處理的任務。
keepAliveTime(線程活動保持時間):線程池的工作線程空閑後,保持存活的時間。所以如果任務很多,並且每個任務執行的時間比較短,可以調大這個時間,提高線程的利用率。
TimeUnit(線程活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
int righesSize=rights.size(); //獲取需要對數據連接的次數
final CountDownLatch countDownLatch=new CountDownLatch(righesSize); //並發工具用於堵塞等待線程執行完成
ExecutorService executorService= Executors.newCachedThreadPool();//使用線程池
int nThreads=Runtime.getRuntime().availableProcessors(); //獲取機器的cpu核心數
final Semaphore semp = new Semaphore(nThreads); //限制線程數
for( int i=0;i<righesSize;i++){
final AppRights info=rights.get(i);
Runnable run = new Runnable() { //開始實行線程啦
@Override
public void run() {
try {
// 獲取線程池的許可(有空閑線程的時候)
semp.acquire();
} catch (Exception e) {
e.printStackTrace();
}
//業務邏輯處理
// for (AppRights info : rights) { //效率不高
MenuCountVo vo = new MenuCountVo();
vo.setMenuId(info.getMenuId());
int notReadCount = 0;
String menuCode = info.getMenuCode();
try {
switch (menuCode) {
case "notice":
//調用天使
JSONObject json = new JSONObject();
json.put("userCode", userCode);
json.put("source", "sfa");
notReadCount = infomationService.getUnreadInform(json);
break;
case "sfa_store_patrol":
notReadCount = storePatrolService.getNotLeaveStoreNum(userCode);//統計門店巡檢未離店記錄
break;
case "sfa_store_order_mrg"://統計門店訂單的未讀數角標,add by Deco 20171012
notReadCount = storeOrderService.getCornerNum(userCode);
break;
}
} catch (Exception e) {
notReadCount = 0;
e.printStackTrace();
}
vo.setNotReadCount(notReadCount);
menuCountList.add(vo);
// 業務邏輯處理完後,釋放線程及堵塞
semp.release();
countDownLatch.countDown();
}
};
executorService.execute(run);
}
countDownLatch.await(); //全部執行完成之後就往下執行啦
return new JsonResult(ApiCode.OK, Boolean.TRUE).data("menuCountList", menuCountList);
}
default :new JsonResult(ApiCode.EXCEPTION, Boolean.TRUE);
}
參考資料
Java並發編程實戰。
JDK1.8源碼。
Java線程池Executor使用