1. TaskExecutor

Spring asynchronous thread pool interface class, its essence is a Java. Util. Concurrent. The Executor

SimpleAsyncTaskExecutor: Not a real thread pool. This class does not reuse threads and creates a new thread each time it is called. 2. SyncTaskExecutor: This class does not implement an asynchronous call, just a synchronous operation. 3. ConcurrentTaskExecutor: Executor adaptation class. This class is not recommended. If ThreadPoolTaskExecutor don’t meet the requirements, only use to consider using this class 4. SimpleThreadPoolTaskExecutor: is Quartz SimpleThreadPool class. 5. ThreadPoolTaskExecutor: Most commonly used, recommended. The essence of which is the Java. Util. Concurrent. ThreadPoolExecutor packaging

2. @Async

Spring defines asynchronous tasks against @async

There are three asynchronous methods: 1. The simplest asynchronous call, which returns void 2. Async calls with arguments Async methods can pass arguments 3. Exception calls return a Future

See the code for details:

@Component public class AsyncDemo { private static final Logger log = LoggerFactory.getLogger(AsyncDemo.class); Void */ @async public void asyncInvokeSimplest() {log.info(" asynccss "); void */ @async public void asyncInvokeSimplest() {log.info(" asynccss "); } /** * Async public void asyncInvokeWithParameter(String s) { log.info("asyncInvokeWithParameter, parementer={}", s); } /** * @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; }}Copy the code

The above asynchronous method is the same as a normal method call

asyncDemo.asyncInvokeSimplest();
asyncDemo.asyncInvokeWithException("test");
Future<String> future = asyncDemo.asyncInvokeReturnFuture(100);
System.out.println(future.get());Copy the code

3. Spring enables asynchronous configuration

Spring has two ways to start the configuration: 1. annotations 2. XML

3.1 Through annotations

To enable the exception method, you also need the following configuration: 1. @enableAsync This annotation enables the asynchronous call function. 2. If not, the system default thread pool is used.

@ SpringBootApplication @ EnableAsync / / start asynchronous calls public class AsyncApplicationWithAnnotation {private static final Logger log = LoggerFactory.getLogger(AsyncApplicationWithAnnotation.class); /** * custom asynchronous thread pool * @return */ @bean public AsyncTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setThreadNamePrefix("Anno-Executor"); executor.setMaxPoolSize(10); / / set to refuse strategy executor. SetRejectedExecutionHandler (new RejectedExecutionHandler () {@ Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { // ..... }}); / / use predefined exception handling class / / executor setRejectedExecutionHandler (new ThreadPoolExecutor. CallerRunsPolicy ()); return executor; } public static void main(String[] args) { log.info("Start AsyncApplication.. "); SpringApplication.run(AsyncApplicationWithAnnotation.class, args); }}Copy the code

The above exception method is the same as a normal method call

@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(100); System.out.println(future.get()); }}Copy the code

Execute the test case and the output reads as follows: You can see that the main thread is named main; The asynchronous method uses anno-executor1, so the exception thread pool works

The 2017-03-28 20:00:07. 5144-731 the INFO/Anno - Executor1 c. ry. Spring. Async. The annotation. AsyncDemo: AsyncSimplest 20:00:07 2017-03-28. 5144-732 the INFO/Anno - Executor1 c. ry. Spring. Async. The annotation. AsyncDemo: asyncInvokeWithParameter, Parementer = test 20:00:07 2017-03-28. 5144-751 the INFO/Anno - Executor1 c. ry. Spring. Async. The annotation. AsyncDemo: asyncInvokeReturnFuture, Parementer = 100 success: 100 2017-03-28 20:00:08. 5144-757 the INFO/Thread - 2 S.C.A.A nnotationConfigApplicationContext: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@47af7f3d: startup date [Tue Mar 28 20:00:06 CST 2017]; root of context hierarchyCopy the code

3.2 Implemented through XML

Bean file configuration: spring_async.xml 1. Thread prefix is xmlExecutor 2. Start asynchronous thread pool configuration

<! -- equivalent to @enableAsync, executor specifies a thread pool --> < Task :annotation-driven Executor ="xmlExecutor"/> <! --> <task:executor id="xmlExecutor" pool-size="5-25" queue-capacity="100" keep-alive="120" rejection-policy="CALLER_RUNS"/>Copy the code

Id: indicates the prefix of the thread name. 2. Pool-size: indicates the size of the thread pool. Support range “min-max” and fixed value (in this case thread pool core and Max sizes are the same) ○ The main idea is that when a task is submitted, The executor will first try to use a free thread if the number of active threads is currently less than the core size. ○ If the core size has been reached, ○ Only then will the task be added to the queue as long as its capacity has not yet been reached. If the queue’s capacity has been reached, Will the executor create a new thread beyond the core size. Then the executors will reject the tasks. ○ By default, the queue is unbounded. but this is rarely the desired configuration because it can lead to OutOfMemoryErrors if enough tasks are added to that Queue while all pool threads are busy. ‘Rejection -policy’ : To reject the task of handling strategy “In the default ThreadPoolExecutor. AbortPolicy, The handler throws a runtime RejectedExecutionException upon rejection. The author In ThreadPoolExecutor. CallerRunsPolicy, the thread that invokes execute itself runs the task. This provides a simple feedback control mechanism that will slow Down the rate that new tasks are submitted. The author In ThreadPoolExecutor. DiscardPolicy, A task that always be executed is simple dropped. The author In ThreadPoolExecutor. DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, Execution is retried (which can fail again, causing this to be repeated.) Whatever determines the time limit (in seconds) for which threads may remain idle before being terminated. If there are more than the core number of threads currently in the pool, after waiting this amount of time without processing a task, excess threads will get terminated. A time value of zero will cause excess threads to terminate immediately after executing a task without remaining follow-up work in the task queue()

Asynchronous thread pool

@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); }}Copy the code

The test case

@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()); }}Copy the code

Run the test case and the output looks like this: You can see that the main thread is named main; The asynchronous method uses xmlExecutor-x, so the exception thread pool is in effect

The 20:12:10 2017-03-28. 12948-540 the INFO [main] C.H.S.A.X ml. AsyncApplicationWithXMLTest: Started AsyncApplicationWithXMLTest in 1.441 seconds (JVM running 2.201) for the 2017-03-28 20:12:10. 12948-718 the INFO [ xmlExecutor-2] com.hry.spring.async.xml.AsyncDemo : asyncInvokeWithParameter, Parementer = test 20:12:10 2017-03-28. 12948-721 the INFO] [xmlExecutor - 1 com. Hry. Spring. Async. XML. AsyncDemo: AsyncSimplest 20:12:10 2017-03-28. 12948-722 the INFO/xmlExecutor - 3 com. Hry. Spring. Async. XML. AsyncDemo: asyncInvokeReturnFuture, Parementer = 100 success: 100 2017-03-28 20:12:11. 12948-729 the INFO/Thread - 2 S.C.A.A nnotationConfigApplicationContext:  Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@71809907: startup date [Tue Mar 28 20:12:09 CST 2017]; root of context hierarchyCopy the code

4. Exception handling of asynchronous methods

When a method is called, it is possible to throw an exception in the method. There are two main types of exception handling in asynchrony: 1. For asynchronous methods that return Futrue: a) catch the exception when calling the future’s GET; B) directly in the abnormal way catch exceptions (2) for the return value is void of asynchronous method: through AsyncUncaughtExceptionHandler handle exceptions

AsyncExceptionDemo:

@Component public class AsyncExceptionDemo { private static final Logger log = LoggerFactory.getLogger(AsyncExceptionDemo.class); Void */ @async public void asyncInvokeSimplest() {log.info(" asynccss "); void */ @async public void asyncInvokeSimplest() {log.info(" asynccss "); } /** * Async calls with arguments async methods can pass arguments * for return value void, Exceptions will be handled with AsyncUncaughtExceptionHandler * * / @ @ param s Async public void asyncInvokeWithException (String s) { log.info("asyncInvokeWithParameter, parementer={}", s); throw new IllegalArgumentException(s); } / back to the Future * * * * abnormal call for the return value is the Future, will not be AsyncUncaughtExceptionHandler processing, * * @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); throw new IllegalArgumentException("a"); } catch (InterruptedException e) { future = new AsyncResult<String>("error"); } catch(IllegalArgumentException e){ future = new AsyncResult<String>("error-IllegalArgumentException"); } return future; }}Copy the code

Implement AsyncConfigurer interface more granular control of abnormal thread pool) to create its own thread pool thread b) method of void class AsyncUncaughtExceptionHandler thrown exception handling

/** * By implementing AsyncConfigurer custom exception thread pool, * * @author hry * */ @service public class MyAsyncConfigurer implements AsyncConfigurer{private static final Logger log = LoggerFactory.getLogger(MyAsyncConfigurer.class); @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor(); threadPool.setCorePoolSize(1); threadPool.setMaxPoolSize(1); threadPool.setWaitForTasksToCompleteOnShutdown(true); threadPool.setAwaitTerminationSeconds(60 * 15); threadPool.setThreadNamePrefix("MyAsync-"); threadPool.initialize(); return threadPool; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new MyAsyncExceptionHandler(); } / custom exception handling class * * * * @ author hry * * / class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {@ Override public void handleUncaughtException(Throwable throwable, Method method, Object... obj) { log.info("Exception message - " + throwable.getMessage()); log.info("Method name - " + method.getName()); for (Object param : obj) { log.info("Parameter value - " + param); }}}}Copy the code
@ SpringBootApplication @ EnableAsync / / start asynchronous calls public class AsyncApplicationWithAsyncConfigurer {private static final Logger log = LoggerFactory.getLogger(AsyncApplicationWithAsyncConfigurer.class); public static void main(String[] args) { log.info("Start AsyncApplication.. "); SpringApplication.run(AsyncApplicationWithAsyncConfigurer.class, args); }}Copy the code

The test code

@RunWith(SpringRunner.class) @SpringBootTest(classes=AsyncApplicationWithAsyncConfigurer.class) public class AsyncApplicationWithAsyncConfigurerTests { @Autowired private AsyncExceptionDemo asyncDemo; @Test public void contextLoads() throws InterruptedException, ExecutionException { asyncDemo.asyncInvokeSimplest(); asyncDemo.asyncInvokeWithException("test"); Future<String> future = asyncDemo.asyncInvokeReturnFuture(100); System.out.println(future.get()); }}Copy the code

Run the test case MyAsyncConfigurer to catch the exception when the AsyncExceptionDemo object calls the asyncInvokeWithException

16:01:45 2017-04-02. 11152-591 the INFO [MyAsync - 1] C.H.S.A.E xception. AsyncExceptionDemo: AsyncSimplest 16:01:45 2017-04-02. 11152-605 the INFO] [MyAsync - 1 C.H.S.A.E xception. AsyncExceptionDemo: asyncInvokeWithParameter, Parementer = test 16:01:45 2017-04-02. 11152-608 the INFO] [MyAsync - 1 C.H.S.A sync. Exception. MyAsyncConfigurer: The Exception message - test the 2017-04-02 16:01:45. 11152-608 the INFO] [MyAsync - 1 C.H.S.A sync. Exception. MyAsyncConfigurer: 2017-04-02 16:01:45.608 INFO 11152 -- [myasync-1] c.h.s.async.exception.MyAsyncConfigurer : The Parameter value - test the 2017-04-02 16:01:45. 11152-608 the INFO] [MyAsync - 1 C.H.S.A.E xception. AsyncExceptionDemo: asyncInvokeReturnFuture, Parementer =100 error-illegalArgumentException 2017-04-02 16:01:46.656 INFO 11152 -- [Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@47af7f3d: startup date [Sun Apr 02 16:01:44 CST 2017]; root of context hierarchyCopy the code

5. Source address

GITHUB address of the code