背景
web请求的时候,有时候会遇到后台操作耗时特别久的操作,前端UI界面总是会请求超时。
举例
代码
@Servicepublic class AsyncTaskService {private Logger logger = LoggerFactory.getLogger(AsyncTaskService.class);public String uuid(){try{TimeUnit.MILLISECONDS.sleep(5000);logger.info("working thread");} catch (InterruptedException e) {logger.error("uuid error ", e);}return UUID.randomUUID().toString();}}
@RestControllerpublic class AsyncController {@AutowiredAsyncTaskService asyncTaskService;@GetMapping("blockingrequest")public String blockingRequest() {logger.info("blockingRequest: start");String uuid = asyncTaskService.uuid();logger.info("blockingRequest: end");return uuid;}}
结果:
目标
开一个子线程异步执行耗时任务。
解决方案
1. @Async
public class AsyncTaskService {@Asyncpublic String getUuid() {try {TimeUnit.MILLISECONDS.sleep(5000);logger.info("working thread");} catch (InterruptedException e) {logger.error("getUuid error ", e);}return UUID.randomUUID().toString();}}
@RestControllerpublic class AsyncController {@AutowiredAsyncTaskService asyncTaskService;@GetMapping("asyncMethod")public String asyncMethod() {logger.info("asyncMethod: start");String uuid = asyncTaskService.getUuid();logger.info("asyncMethod: end");return uuid;}}
5s后返回response。
2. Callable
@RestControllerpublic class AsyncController {@AutowiredAsyncTaskService asyncTaskService;@GetMapping("callable")public Callable<String> callable() {logger.info("callable: start");Callable<String> callable = () -> {String uuid = asyncTaskService.uuid();logger.info("child task thread");return uuid;};logger.info("callable: end");return callable;}}
5s后返回response。虽然先打印了”callable: end”,但是还是会等到线程返回结果后,再返回给UI。还是会超时。
3. DefferedResult
@RestControllerpublic class AsyncController {@AutowiredAsyncTaskService asyncTaskService;@GetMapping("deferredResultRequest")public DeferredResult<String> deferredResultRequest() {logger.info("deferredResultRequest: start");DeferredResult<String> deferredResult = new DeferredResult<>(2000l);//可使用线程池// ExecutorService executorService = Executors.newFixedThreadPool(10);// executorService.submit(() -> {// asyncTaskService.uuid(request, response);// deferredResult.setResult("watch:complete");// });new Thread(()-> {asyncTaskService.uuid();deferredResult.setResult("deferredResultRequest:complete");}).start();deferredResult.onTimeout(() -> deferredResult.setResult("deferredResultRequest:timeout"));deferredResult.onCompletion(()->deferredResult.setResult("deferredResultRequest:complete"));deferredResult.onError(throwable -> deferredResult.setErrorResult("deferredResultRequest:error"));logger.info("deferredResultRequest: return");return deferredResult;}}
返回结果:deferredResultRequest:timeout
可在设置的时间内返回结果给UI,不论子线程是否完成。
