|
| 1 | +``` |
| 2 | +1.引入web依赖: |
| 3 | + <dependency> |
| 4 | + <groupId>org.springframework.boot</groupId> |
| 5 | + <artifactId>spring-boot-starter-web</artifactId> |
| 6 | + </dependency> |
| 7 | +2.开启异步支持: (入口类上加上@EnableAsync注解) |
| 8 | + @SpringBootApplication |
| 9 | + @EnableAsync |
| 10 | + public class DemoApplication { |
| 11 | + public static void main(String[] args) { |
| 12 | + SpringApplication.run(DemoApplication.class, args); |
| 13 | + } |
| 14 | + } |
| 15 | +3.编写支持异步调用的服务: |
| 16 | + @Service |
| 17 | + public class TestService { |
| 18 | + //底层默认使用logback |
| 19 | + private Logger logger = LoggerFactory.getLogger(this.getClass()); |
| 20 | + @Async |
| 21 | + public void asyncMethod() { |
| 22 | + sleep(); |
| 23 | + logger.info("异步方法内部线程名称:{}", Thread.currentThread().getName()); |
| 24 | + } |
| 25 | + public void syncMethod() { sleep(); } |
| 26 | + private void sleep() { |
| 27 | + try { |
| 28 | + TimeUnit.SECONDS.sleep(2); |
| 29 | + } catch (InterruptedException e) { |
| 30 | + e.printStackTrace(); |
| 31 | + } |
| 32 | + } |
| 33 | + } |
| 34 | +4.编写测试controller: |
| 35 | + @RestController |
| 36 | + public class TestController { |
| 37 | + private Logger logger = LoggerFactory.getLogger(this.getClass()); |
| 38 | + @Autowired |
| 39 | + private TestService testService; |
| 40 | + @GetMapping("async") |
| 41 | + public void testAsync() { |
| 42 | + long start = System.currentTimeMillis(); |
| 43 | + logger.info("异步方法开始"); |
| 44 | + testService.asyncMethod(); |
| 45 | + logger.info("异步方法结束"); |
| 46 | + long end = System.currentTimeMillis(); |
| 47 | + logger.info("总耗时:{} ms", end - start); |
| 48 | + } |
| 49 | + @GetMapping("sync") |
| 50 | + public void testSync() { |
| 51 | + long start = System.currentTimeMillis(); |
| 52 | + logger.info("同步方法开始"); |
| 53 | + testService.syncMethod(); |
| 54 | + logger.info("同步方法结束"); |
| 55 | + long end = System.currentTimeMillis(); |
| 56 | + logger.info("总耗时:{} ms", end - start); |
| 57 | + } |
| 58 | + } |
| 59 | +5.启动项目,分别测试同步方法和异步方法的调用: |
| 60 | + 同步: http://localhost:8080/sync |
| 61 | + 同步方法开始 |
| 62 | + 同步方法结束 |
| 63 | + 总耗时:2004 ms |
| 64 | + 异步: http://localhost:8080/async |
| 65 | + 异步方法开始 |
| 66 | + 异步方法结束 |
| 67 | + 总耗时:4 ms |
| 68 | + 异步方法内部线程名称:task-1 |
| 69 | + (当遇到异步方法时,会新启一个线程来执行异步方法) |
| 70 | + (默认情况下的异步线程池配置使得线程不能被重用,每次调用异步方法都会新建一个线程) |
| 71 | +6.自定义异步线程池: |
| 72 | + [1]自定义线程池的配置(使用ThreadPoolTaskExecutor的方法): |
| 73 | + corePoolSize: 线程池核心线程的数量,默认值为1;(默认异步线程池配置使得线程不能被重用的原因) |
| 74 | + maxPoolSize: 线程池维护的线程的最大数量,默认值为Integer.MAX_VALUE; |
| 75 | + 只有当核心线程都被用完并且缓冲队列满后,才会开始申超过请核心线程数的线程; |
| 76 | + queueCapacity: 缓冲队列; |
| 77 | + keepAliveSeconds: 超出核心线程数外的线程在空闲时候的最大存活时间,默认为60秒; |
| 78 | + threadNamePrefix: 线程名前缀; |
| 79 | + waitForTasksToCompleteOnShutdown: 是否等待所有线程执行完毕才关闭线程池,默认值为false; |
| 80 | + awaitTerminationSeconds: waitForTasksToCompleteOnShutdown的等待的时长,默认值为0,即不等待; |
| 81 | + rejectedExecutionHandler: 当没有线程可以被使用时的处理策略(拒绝任务),默认策略为abortPolicy; |
| 82 | + 包含下面四种策略: |
| 83 | + callerRunsPolicy: 用于被拒绝任务的处理程序,它直接在execute方法的调用线程中运行被拒绝的任务; |
| 84 | + 如果执行程序已关闭,则会丢弃该任务; |
| 85 | + abortPolicy: 直接抛出java.util.concurrent.RejectedExecutionException异常; |
| 86 | + discardOldestPolicy: 当线程池中的数量等于最大线程数时,抛弃线程池中最后一个要执行的任务, |
| 87 | + 并执行新传入的任务; |
| 88 | + discardPolicy: 当线程池中的数量等于最大线程数时,不做任何动作; |
| 89 | + [2]添加自定义异步线程: |
| 90 | + @Configuration |
| 91 | + public class AsyncPoolConfig { |
| 92 | + @Bean |
| 93 | + public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor(){ |
| 94 | + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
| 95 | + executor.setCorePoolSize(20); |
| 96 | + executor.setMaxPoolSize(200); |
| 97 | + executor.setQueueCapacity(25); |
| 98 | + executor.setKeepAliveSeconds(200); |
| 99 | + executor.setThreadNamePrefix("asyncThread"); |
| 100 | + executor.setWaitForTasksToCompleteOnShutdown(true); |
| 101 | + executor.setAwaitTerminationSeconds(60); |
| 102 | + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); |
| 103 | + executor.initialize(); |
| 104 | + return executor; |
| 105 | + } |
| 106 | + } |
| 107 | + [3]使用自定义异步线程池时,@Async注解需指定线程池Bean名称: |
| 108 | + @Service |
| 109 | + public class TestService { |
| 110 | + ...... |
| 111 | + @Async("asyncThreadPoolTaskExecutor") |
| 112 | + public void asyncMethod() { |
| 113 | + ...... |
| 114 | + } |
| 115 | + ...... |
| 116 | + } |
| 117 | +7.处理异步回调: |
| 118 | + [1]Future及其实现类的关系: |
| 119 | + Future(接口) --> ListenableFuture(接口) --> AsyncResult(类,Spring实现的Future实现类) |
| 120 | + @Async("asyncThreadPoolTaskExecutor") |
| 121 | + public Future<String> asyncMethod() { |
| 122 | + sleep(); |
| 123 | + logger.info("异步方法内部线程名称:{}", Thread.currentThread().getName()); |
| 124 | + return new AsyncResult<>("hello async"); |
| 125 | + } |
| 126 | + [2]异步回调的具体使用: |
| 127 | + (1)在service的异步方法中使用Future包装需要返回的对象: |
| 128 | + @Service |
| 129 | + public class TestReturnService { |
| 130 | + //底层默认使用logback |
| 131 | + private Logger logger = LoggerFactory.getLogger(this.getClass()); |
| 132 | + @Async("asyncThreadPoolTaskExecutor") |
| 133 | + public Future<String> asyncReturnMethod(){ |
| 134 | + sleep(); |
| 135 | + logger.info("异步方法内部线程名称:{}", Thread.currentThread().getName()); |
| 136 | + return new AsyncResult<>("hello async"); |
| 137 | + } |
| 138 | + private void sleep() { |
| 139 | + try { |
| 140 | + TimeUnit.SECONDS.sleep(2); |
| 141 | + } catch (InterruptedException e) { |
| 142 | + e.printStackTrace(); |
| 143 | + } |
| 144 | + } |
| 145 | + } |
| 146 | + (2)在调用异步方法的地方,使用Future接口的get方法获取异步方法真实返回的对象: |
| 147 | + @RestController |
| 148 | + public class TestController { |
| 149 | + private Logger logger = LoggerFactory.getLogger(this.getClass()); |
| 150 | + @Autowired |
| 151 | + private TestService testService; |
| 152 | + @Autowired |
| 153 | + private TestReturnService testReturnService; |
| 154 | + @GetMapping("asyncReturn") |
| 155 | + public String testAsyncReturn() throws ExecutionException, InterruptedException { |
| 156 | + long start = System.currentTimeMillis(); |
| 157 | + logger.info("异步方法开始"); |
| 158 | + Future<String> stringFuture = testReturnService.asyncReturnMethod(); |
| 159 | + String result = stringFuture.get(); |
| 160 | + logger.info("异步方法返回值:{}", result); |
| 161 | + logger.info("异步方法结束"); |
| 162 | + long end = System.currentTimeMillis(); |
| 163 | + logger.info("总耗时:{} ms", end - start); |
| 164 | + return result; |
| 165 | + } |
| 166 | + (Future的get方法为阻塞方法,只有当异步方法返回内容了,程序才会继续往下执行;) |
| 167 | + (get(long timeout, TimeUnit unit)重载方法可设置超时时间,即异步方法在设定时间内没有返回值的话, |
| 168 | + 直接抛出java.util.concurrent.TimeoutException异常) |
| 169 | +``` |
0 commit comments