1、Callable
Callable的异步实现,需要主线程调用副线程来实现
import java.util.concurrent.Callable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AsyncController {
private Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/callableOrder")
public Callable<String> callableOrder() {
logger.info("主线程开始");
//创建新线程,在主线程中调用
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
logger.info("副线程开始");
Thread.sleep(3000);
logger.info("副线程结束");
return "success";
}
};
logger.info("主线程结束");
return callable;
}
}
测试结果:
2019-05-16 21:55:00.688 INFO 5716 --- [nio-8080-exec-1] com.llangzh.controller.AsyncController : 主线程开始
2019-05-16 21:55:00.690 INFO 5716 --- [nio-8080-exec-1] com.llangzh.controller.AsyncController : 主线程结束
2019-05-16 21:55:00.702 INFO 5716 --- [ MvcAsync1] com.llangzh.controller.AsyncController : 副线程开始
2019-05-16 21:55:03.704 INFO 5716 --- [ MvcAsync1] com.llangzh.controller.AsyncController : 副线程结束
通过测试结果可以看出,主线程只是将任务交给副线程就结束了,而副线程经过3秒返回。
2、DeferredResult
DeferredResult实现异步,并不需要通过主线程来启动副线程
package com.llangzh.bean;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;
@Component
public class DeferredResultHandler {
private Map<String, DeferredResult<String>> map = new HashMap<String, DeferredResult<String>>();
public Map<String, DeferredResult<String>> getMap() {
return map;
}
public void setMap(Map<String, DeferredResult<String>> map) {
this.map = map;
}
}
package com.llangzh.bean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 模拟队列
* @author Administrator
*
*/
@Component
public class MockQueue {
//请求来时的信息
private String placeOrder;
//请求处理结束信息
private String completeOrder;
private Logger logger = LoggerFactory.getLogger(getClass());
public String getPlaceOrder() {
return placeOrder;
}
/**
* 模拟请求处理过程
*
* @param placeOrder
*/
public void setPlaceOrder(String placeOrder) {
new Thread(() -> {
logger.info("接收到下单请求"+placeOrder);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.completeOrder = placeOrder;
logger.info("下单请求处理完毕"+placeOrder);
}).start();
}
public String getCompleteOrder() {
return completeOrder;
}
public void setCompleteOrder(String completeOrder) {
this.completeOrder = completeOrder;
}
}
添加 ApplicationListener 监听
package com.llangzh.listen;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import com.llangzh.bean.DeferredResultHandler;
import com.llangzh.bean.MockQueue;
/**
* 请求处理监听器
* @author Administrator
*
*/
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent>{
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHandler handler;
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
new Thread(() -> {
while(true) {
//mockQueue.getCompleteOrder()不是空值,说明请求已经处理完了
if(StringUtils.isNotBlank(mockQueue.getCompleteOrder())) {
//获取请求key
String orderNumber = mockQueue.getCompleteOrder();
handler.getMap().get(orderNumber).setResult("请求处理结束");
logger.info("返回请求处理结果"+orderNumber);
//清空请求
mockQueue.setCompleteOrder(null);
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
添加 Controller 处理器
package com.llangzh.controller;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import com.llangzh.bean.DeferredResultHandler;
import com.llangzh.bean.MockQueue;
@RestController
public class AsyncController {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHandler handler;
@RequestMapping("/deferredResultOrder")
public DeferredResult<String> deferredResultOrder() {
logger.info("主线程开始");
// 常见随机的8位数字,设置为请求的key
String orderNumber = RandomStringUtils.randomNumeric(8);
mockQueue.setPlaceOrder(orderNumber);
DeferredResult<String> result = new DeferredResult<String>();
handler.getMap().put(orderNumber, result);
logger.info("主线程结束");
return result;
}
}
测试结果:
2019-05-16 22:14:11.059 INFO 5336 --- [nio-8080-exec-2] com.llangzh.controller.AsyncController : 主线程开始
2019-05-16 22:14:11.065 INFO 5336 --- [ Thread-11] com.llangzh.bean.MockQueue : 接收到下单请求67085016
2019-05-16 22:14:11.065 INFO 5336 --- [nio-8080-exec-2] com.llangzh.controller.AsyncController : 主线程结束
2019-05-16 22:14:14.066 INFO 5336 --- [ Thread-11] com.llangzh.bean.MockQueue : 下单请求处理完毕67085016
2019-05-16 22:14:14.154 INFO 5336 --- [ Thread-8] com.llangzh.listen.QueueListener : 返回请求处理结果67085016
可以看到,并没有在主程序中调用处理任务的线程,而是通过监听的方式
这篇博客探讨了Spring Boot中使用Callable和DeferredResult实现异步处理的两种方式。Callable需要主线程启动副线程,而DeferredResult则可以通过ApplicationListener监听实现异步,不需额外启动线程。
1万+

被折叠的 条评论
为什么被折叠?



