合理使用異步線程開發項目能提高一個項目的並發量,減少響應時間。下面就簡單介紹一下異步線程池的使用,參考博客:https://blog.csdn.net/hry2015/article/details/67640534
spring 對@Async定義異步任務的方法有3種:
1.最簡單的異步調用,返回值為void;
2.帶參數的異步調用,異步方法可以傳入參數;
3.異常調用返回Future
代碼如下:
package com.hry.spring.async.annotation;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
/**
* 異步方法調用
*
* @author hry
*
*/
@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;
}
}
spring啟動配置的方式有兩種:
1.注解;
2.XML配置文件
我們先說注解的方式:
@EnableAsync注解可以開啟異步調用功能, public AsyncTaskExecutor taskExecutor() 方法自定義自己的線程池,線程池前綴”Anno-Executor”。如果不定義,則使用系統默認的線程池。代碼如下:
package com.hry.spring.async.annotation;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 通過@EnableAsync啟動異步方法
* @author hry
*
*/
@SpringBootApplication
@EnableAsync // 啟動異步調用
public class AsyncApplicationWithAnnotation {
private static final Logger log = LoggerFactory.getLogger(AsyncApplicationWithAnnotation.class);
/**
* 自定義異步線程池
* 如果沒有這個方法,則使用默認的線程池
* @return
*/
@Bean
public AsyncTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("Anno-Executor");//設置線程名稱的前綴
executor.setCorePoolSize(5);//設置核心線程數
executor.setMaxPoolSize(10);//設置最大線程數
// 設置拒絕策略
executor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// .....
}
});
// 使用預定義的異常處理類
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
public static void main(String[] args) {
log.info("Start AsyncApplication.. ");
SpringApplication.run(AsyncApplicationWithAnnotation.class, args);
}
}
現在寫測試類:
package com.hry.spring.async.annotation;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.hry.spring.async.annotation.AsyncApplicationWithAnnotation;
import com.hry.spring.async.annotation.AsyncDemo;
@RunWith(SpringRunner.class)
@SpringBootTest(classes=AsyncApplicationWithAnnotation.class)
public class AsyncApplicationWithAnnotationTests {
@Autowired
private AsyncDemo asyncDemo;
@Test
public void contextLoads() throws InterruptedException, ExecutionException {
asyncDemo.asyncInvokeSimplest();
asyncDemo.asyncInvokeWithParameter("test");
Future<String> future = asyncDemo.asyncInvokeReturnFuture(1000);
System.out.println(future.get());
}
}
啟動測試類,結果如下:

說明啟動異步線程池成功,執行上面的3個方法分別用了3個線程。
再說一下XML配置文件配置的方式:
我們先創建XML配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"
default-lazy-init="false">
<!-- 等價於 @EnableAsync, executor指定線程池 -->
<task:annotation-driven executor="xmlExecutor"/>
<!-- id指定線程池產生線程名稱的前綴 -->
<task:executor
id="xmlExecutor"
pool-size="3-20"
queue-capacity="100"
keep-alive="120"
rejection-policy="CALLER_RUNS"/>
</beans>
其中id表示線程名稱的前綴,pool-size表示線程池的大小,“3-20”表示線程池的最大線程數為20,最小線程數為3,也可以設置成一個值,如:pool-size=5,則表示線程池的核心線程數和最大線程數相同,都是5。queue-capacity表示排隊隊列的長度。
項目啟動時讀取xml配置文件,如下:
package com.hry.spring.async.xml;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
/**
* 通過XML啟動異步
* @author hry
*
*/
@SpringBootApplication
@ImportResource("classpath:/async/spring_async.xml")
public class AsyncApplicationWithXML {
private static final Logger log = LoggerFactory.getLogger(AsyncApplicationWithXML.class);
public static void main(String[] args) {
log.info("Start AsyncApplication.. ");
SpringApplication.run(AsyncApplicationWithXML.class, args);
}
}
編寫測試類:
package com.hry.spring.async.xml;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes=AsyncApplicationWithXML.class)
public class AsyncApplicationWithXMLTest {
@Autowired
private AsyncDemo asyncDemo;
@Test
public void contextLoads() throws InterruptedException, ExecutionException {
asyncDemo.asyncInvokeSimplest();
asyncDemo.asyncInvokeWithParameter("test");
Future<String> future = asyncDemo.asyncInvokeReturnFuture(100);
System.out.println(future.get());
}
}
測試結果如下:

測試成功。
