1. 程式人生 > >Java執行緒池的實現--Executor、ThreadPoolTaskExecutor、@Async的使用

Java執行緒池的實現--Executor、ThreadPoolTaskExecutor、@Async的使用

一、為什麼要使用執行緒池

當我們需要的併發執行執行緒數量很多時,且每個執行緒執行很短的時間就結束了,這樣,我們頻繁的建立、銷燬執行緒就大大降低了工作效率(建立和銷燬執行緒需要時間、資源)。java中的執行緒池可以達到這樣的效果:一個執行緒執行完任務之後,繼續去執行下一個任務,不被銷燬,這樣執行緒利用率提高了。

二、Jdk 1.5後執行緒池

    //【固定的執行緒池】定義程序池並指定其大小  
    ExecutorService threadPool = Executors.newFixedThreadPool(3);

    for(int i=1;i<=10
;i++){ final int task = i; threadPool.execute(new Runnable(){ @Override public void run() { for(int j=1;j<=2;j++){ try { Thread.sleep(20); } catch
(InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is looping of " + j + " for task of " + task); } } }); }

java.util.concurrent.Executor

介面表示執行緒池,它的execute(Runnable task)用來執行Runnable型別的任務。Executor的子介面ExecutorService中聲明瞭管理執行緒池的一些方法,比如關閉執行緒池的shutdown()等。Executors類中包含了一些靜態方法,生成各種型別的執行緒池ExecutorService例項

三、Spring非同步執行緒池

非同步呼叫

在解釋非同步呼叫之前,我們先來看同步呼叫的定義;同步就是整個處理過程順序執行,當各個過程都執行完畢,並返回結果。 非同步呼叫則是隻是傳送了呼叫的指令,呼叫者無需等待被呼叫的方法完全執行完畢;而是繼續執行下面的流程。

1、TaskExecutor

TaskExecutor是Spring非同步執行緒池的介面類,其實質是java.util.concurrent.Executor。

Spring 已經實現的異常執行緒池:

  1. SimpleAsyncTaskExecutor:不是真的執行緒池,每次呼叫都會建立一個新的執行緒。
  2. SyncTaskExecutor:這個類沒有實現非同步呼叫,只是一個同步操作。只適用於不需要多執行緒的地方。
  3. ConcurrentTaskExecutor:Executor的適配類,不推薦使用。如果ThreadPoolTaskExecutor不滿足要求時,才用考慮使用這個類。
  4. SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的類。執行緒池同時被quartz和非quartz使用,才需要使用此類。
  5. ThreadPoolTaskExecutor:最常使用,推薦。 其實質是對java.util.concurrent.ThreadPoolExecutor的包裝。

ThreadPoolTaskExecutor的使用:

//spring.xml配置
<!-- 非同步執行緒池 -->  
<bean id="taskExecutor"  
    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">  
    <!-- 核心執行緒數,執行緒池裡最小執行緒數 -->  
    <property name="corePoolSize" value="10" />  
    <!-- 最大執行緒數 -->  
    <property name="maxPoolSize" value="100" />  
    <!-- 佇列最大長度 -->  
    <property name="queueCapacity" value="1000" />  
    <!-- 執行緒池維護執行緒所允許的空閒時間 -->  
    <property name="keepAliveSeconds" value="300" />  
    <!-- 執行緒池對拒絕任務(無執行緒可用)的處理策略 -->  
    <property name="rejectedExecutionHandler">  
        <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />  
    </property>  
</bean>  


//從池中獲取執行緒執行任務
public class ThreadPoolTest {  
    @Autowired  
    private TaskExecutor taskExecutor;// 執行緒池  

    // 將建立的執行緒新增到執行緒池中  
    public void test() throws Exception {  
        for (int i = 0; i < 10; i++) {  
            this.taskExecutor.execute(new AppContentDataPushThread());  
        }  
    }  

    class AppContentDataPushThread implements Runnable {  

        public AppContentDataPushThread() {  
        }  

        @Override  
        public void run() {  
            System.out.println("執行執行緒");  
        }  
    }  
}  

2、@Async

2.1、在Spring中啟用@Async

基於註解配置

@Configuration  
@EnableAsync  
public class SpringAsyncConfig { ... }  

基於xml配置

<task:executor id="myexecutor"pool-size="5"/>   
<task:annotation-driven executor="myexecutor"/>  
2.2、使用
@Component
public class AsyncDemo {
    private static final Logger log = LoggerFactory.getLogger(AsyncDemo.class);

    /**
     * 最簡單的非同步呼叫,返回值為void
     */
    @Async
    public void asyncInvokeSimplest() {
        log.info("asyncSimplest");
    }

    /**
     * 帶引數的非同步呼叫 非同步方法可以傳入引數
     * 
     * @param s
     */
    @Async
    public void asyncInvokeWithParameter(String s) {
        log.info("asyncInvokeWithParameter, parementer={}", s);
    }

    /**
     * 異常呼叫返回Future
     * 
     * @param i
     * @return
     */
    @Async
    public Future<String> asyncInvokeReturnFuture(int i) {
        log.info("asyncInvokeReturnFuture, parementer={}", i);
        Future<String> future;
        try {
            Thread.sleep(1000 * 1);
            future = new AsyncResult<String>("success:" + i);
        } catch (InterruptedException e) {
            future = new AsyncResult<String>("error");
        }
        return future;
    }
}

//呼叫
asyncDemo.asyncInvokeSimplest();
asyncDemo.asyncInvokeWithException("test");
Future<String> future = asyncDemo.asyncInvokeReturnFuture(100);
System.out.println(future.get());