1. 程式人生 > >專案中初始化通用執行緒池

專案中初始化通用執行緒池

說明:在專案初始階段,有的時候需要維護一個通用的執行緒池,用來非同步執行寫操作,不影響主執行緒。直接上程式碼吧!

package com.fy.agent.api.config.thread;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import
java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; /** * @author : lqf * @description : 通用執行緒池,用於非同步執行寫操作不影響主執行緒 * @date : Create in 10:47 2018/6/1 */ @Configuration @EnableAsync public class InitThread { //執行緒池維護執行緒的最少數量 private static final int CORE_POOL_SIZE = 10; //執行緒池維護執行緒的最大數量
private static final int MAX_POOL_SIZE = 50; //快取佇列 private static final int QUEUE_CAPACITY = 10; //允許的空閒時間 private static final int KEEP_ALIVE = 60; @Bean public Executor myExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(CORE_POOL_SIZE); executor.setMaxPoolSize(MAX_POOL_SIZE); executor.setQueueCapacity(QUEUE_CAPACITY); executor.setThreadNamePrefix("executor-"
); /* * 使用此策略,如果新增到執行緒池失敗,那麼主執行緒會自己去執行該任務,不會等待執行緒池中的執行緒去執行 */ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setKeepAliveSeconds(KEEP_ALIVE); executor.initialize(); return executor; } }

這裡想對拒絕策略RejectedExecutionHandler做一下詳細的介紹。
在使用執行緒池並且使用有界佇列的時候,如果佇列滿了,任務新增到執行緒池的時候就會有問題,針對這些問題java執行緒池提供了以下幾種策略:

  • AbortPolicy
  • DiscardPolicy
  • DiscardOldestPolicy
  • CallerRunsPolicy
  • 自定義

◇AbortPolicy
該策略是執行緒池的預設策略。使用該策略時,如果執行緒池佇列滿了丟掉這個任務並且丟擲RejectedExecutionException異常。
原始碼如下:

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {  
            //不做任何處理,直接丟擲異常  
            throw new RejectedExecutionException("Task" + r.toString() +  
                                                 " rejected from " +  
                                                 e.toString());  
}

◇DiscardPolicy
這個策略和AbortPolicy的slient版本,如果執行緒池佇列滿了,會直接丟掉這個任務並且不會有任何異常。
原始碼如下:

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {  
         //就是一個空的方法  
      }  

◇DiscardOldestPolicy
這個策略從字面上也很好理解,丟棄最老的。也就是說如果佇列滿了,會將最早進入佇列的任務刪掉騰出空間,再嘗試加入佇列。
因為佇列是隊尾進,隊頭出,所以隊頭元素是最老的,因此每次都是移除對頭元素後再嘗試入隊。
原始碼如下:

 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {  
     if (!e.isShutdown()) {  
         //移除隊頭元素  
         e.getQueue().poll();  
         //再嘗試入隊  
         e.execute(r);  
     }  
 }

CallerRunsPolicy
使用此策略,如果新增到執行緒池失敗,那麼主執行緒會自己去執行該任務,不會等待執行緒池中的執行緒去執行。就像是個急脾氣的人,我等不到別人來做這件事就乾脆自己幹。
原始碼如下:

 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {  
             if (!e.isShutdown()) {  
                 //直接執行run方法  
                 r.run();  
             }  
         }

自定義
如果以上策略都不符合業務場景,那麼可以自己定義一個拒絕策略,只要實現RejectedExecutionHandler介面,並且實現rejectedExecution方法就可以了。具體的邏輯就在rejectedExecution方法裡去定義就OK了。
例如:我定義了我的一個拒絕策略,叫做MyRejectPolicy,裡面的邏輯就是列印處理被拒絕的任務內容

 public class MyRejectPolicy implements RejectedExecutionHandler{  
     public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {  
         //Sender是我的Runnable類,裡面有message欄位  
         if (r instanceof Sender) {  
             Sender sender = (Sender) r;  
             //直接列印  
             System.out.println(sender.getMessage());  
         }  
     }  
 } 

這幾種策略沒有好壞之分,只是適用不同場景,具體哪種合適根據具體場景和業務需要選擇,如果需要特殊處理就自己定義好了