在Spring中,@Async這個注解用於標記的異步的方法。方法上一旦標記了這個方法,當其它線程調用這個方法時,就會開啟一個新的線程去異步處理業務邏輯。
此注解的使用說明:
1、此注解可以用在方法上,也可以用在類上(如果用在類上,這個類中的所有的方法就是異步的)
2、使用此注解的方法的類對象,需要是spring管理下的bean對象
3、程序主類或此注解的主類上,需要開啟啟用異步配置,配置上@EnableAsync注解
以Spring boot 為例,啟動類中增加@EnableAsync,
@EnableAsync
@SpringBootApplication
public class ManageApplication {
}
異步類:
@Component
public class MyAsyncTask {
@Async
public void asyncCpsItemImportTask(Long platformId, String jsonList){}
}
上面的配置會啟用默認的執行器,異步執行指定的方法。
在業務場景中,有時需要使用自己定義的執行器來跑異步的業務邏輯,那該怎么辦呢?
上面的改造后的代碼如下:
@EnableAsync
@SpringBootApplication
public class ManageApplication {
@Bean("MyExecutor")
public TaskExecutor workExecutor1(){
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("parseMyTask");
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(30);
threadPoolTaskExecutor.setQueueCapacity(100);
threadPoolTaskExecutor.afterPropertiesSet();
return threadPoolTaskExecutor;
}
}
異步類:
@Component
public class MyAsyncTask {
@Async("MyExecutor")
public void asyncCpsItemImportTask(Long platformId, String jsonList){}
}
注:
1、 @Async注解由於是異步執行的,在其調用數據庫操作之時,將無法產生事務管理的控制。解決辦法,可以把@Transactional注解放到內部的需要進行事務的方法上
2、異步的業務邏輯處理場景 有兩種,一個是不需要返回結果,另一種是需要接收返回結果。
不需要返回結果的比較簡單,就不多說了。
需要接收返回結果的示例如下:
@Async("MyExecutor")
public Future<Map<Long, List>> queryMap(List ids) {
List<> result = businessService.queryMap(ids);
..............
Map<Long, List> resultMap = Maps.newHashMap();
...
return new AsyncResult<>(resultMap);
}
調用的方法示例:
private Map asyncCollectProcessAbilities(List<BindDeviceDO> bindDevices,
List<BindStaffDO> bindStaffs, String dccId) {
// 返回值
Future<Map<Long, List>> asyncResult = MyService.queryMap(ids);
try {
finalMap = asyncResult.get();
} catch (InterruptedException | ExecutionException e) {
...
}
return finalMap;
}
3、關於執行器
Spring用TaskExecutor和TaskScheduler接口提供了異步執行和調度任務的抽象。
Spring的TaskExecutor和java.util.concurrent.Executor接口時一樣的,這個接口只有一個方法execute(Runnable task)。
Spring已經內置了許多TaskExecutor的實現,沒有必要自己去實現:
SimpleAsyncTaskExecutor 這種實現不會重用任何線程,每次調用都會創建一個新的線程。
SyncTaskExecutor 這種實現不會異步的執行
ConcurrentTaskExecutor 這種實現是java.util.concurrent.Executor的一個adapter。
SimpleThreadPoolTaskExecutor 這種實現實際上是Quartz的SimpleThreadPool的一個子類,它監聽Spring的聲明周期回調。
ThreadPoolTaskExecutor 這是最常用最通用的一種實現。它包含了java.util.concurrent.ThreadPoolExecutor的屬性,並且用TaskExecutor進行包裝。
默認是用代理去處理@Async的,因此,相同類中的方法調用帶@Async的方法是無法異步的,這種情況仍然是同步。