
文章插图
本教程大概目录:
- 模拟单线程情节
- 用Callable实现 并发编程
- 用DeferedResult实现异步处理
/** * Created by Fant.J. */@RestController@Slf4jpublic class AsyncController {/*** 单线程测试* @return* @throws InterruptedException*/@RequestMApping("/order")public String order() throws InterruptedException {log.info("主线程开始");Thread.sleep(1000);log.info("主线程返回");return "success";}}我们把线程休息一秒当作模拟处理业务所花费的时间 。很明显能看出来,这是个单线程 。
文章插图
nio-8080-exec-1表示主线程的线程1 。

文章插图
用Callable实现 并发编程
/*** 用Callable实现异步* @return* @throws InterruptedException*/@RequestMapping("/orderAsync")public Callable orderAsync() throws InterruptedException {log.info("主线程开始");Callable result = new Callable() {@Overridepublic Object call() throws Exception {log.info("副线程开始");Thread.sleep(1000);log.info("副线程返回");return "success";}};log.info("主线程返回");return result;}
文章插图

文章插图
我们可以看到,主线程的开始和返回(结束处理)是首先执行的,然后副线程才执行真正的业务处理 。说明主线程在这里的作用是调用(唤醒)子线程,子线程处理完会返回一个Object对象,然后返回给用户 。
这样虽然实现了并发处理,但是有一个问题,就是主线程和副线程没有做到完全分离,毕竟是一个嵌套进去的副线程 。
所以为了优化我们的实现,我在这里模拟 消息中间件 来实现主线程副线程的完全分离 。
用DeferedResult实现异步处理因为本章主要讲的是并发编程原理 , 所以这里我们不用现成的消息队列来搞,我们模拟一个消息队列来处理 。
MockQueue .JAVA
/** * 模拟消息队列 类 * Created by Fant.J. */@Component@Slf4jpublic class MockQueue {//下单消息private String placeOrder;//订单完成消息private String completeOrder;public String getPlaceOrder() {return placeOrder;}public void setPlaceOrder(String placeOrder) throws InterruptedException {new Thread(()->{log.info("接到下单请求"+placeOrder);//模拟处理try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//给completeOrder赋值this.completeOrder = placeOrder;log.info("下单请求处理完毕"+placeOrder);}).start();}public String getCompleteOrder() {return completeOrder;}public void setCompleteOrder(String completeOrder) {this.completeOrder = completeOrder;}}注意再setPlaceOrder(String placeOrder)方法里 , 我创建了一个新的线程来处理接单的操作(为什么要建立新线程,怕主线程在这挂起,此段逻辑也没有线程安全问题,况且异步处理更快) 。传进来的参数是个 订单号 ,经过1s的处理成功后,把订单号传给completeOrder 字段,说明用户下单成功,我在下面付controller调用该方法的代码 。//注入模拟消息队列类@Autowiredprivate MockQueue mockQueue;@Autowiredprivate DeferredResultHolder deferredResultHolder;....@RequestMapping("/orderMockQueue")public DeferredResult orderQueue() throws InterruptedException {log.info("主线程开始");//随机生成8位数String orderNumber = RandomStringUtils.randomNumeric(8);mockQueue.setPlaceOrder(orderNumber);DeferredResult result = new DeferredResult();deferredResultHolder.getMap().put(orderNumber,result);Thread.sleep(1000);log.info("主线程返回");return result;}好了,然后我们还需要一个中介类来存放订单号和处理结果 。为什么需要这么一个类呢,因为我们之前说过要实现主线程和副线程分离 , 所以需要一个中介来存放处理信息(比如:这个订单号信息,和处理结果信息) , 我们判断处理结果是否为空就知道该副线程执行了没有 。所以我们写一个中介类DeferredResultHolder。######DeferredResultHolder .java:
/** *订单处理情况 中介/持有者 * Created by Fant.J. */@Componentpublic class DeferredResultHolder {/*** String: 订单号* DeferredResult:处理结果*/private Map<String,DeferredResult> map = new HashMap<>();public Map<String, DeferredResult> getMap() {return map;}public void setMap(Map<String, DeferredResult> map) {this.map = map;}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 在SpringBoot中通过Canal实现MySQL与Redis的数据同步
- Linux线程编程指南:并发和同步技术
- Java 21,虚拟线程、结构化并发和作用域值
- 编程一般要学几年 孩子学编程的最佳年龄
- Python编程:利用缓存加速你的应用程序
- SpringBoot拦截器和动态代理有什么区别?
- TypeScript 不是一种编程语言?
- RestTemplate详解 Springboot — 用更优雅的方式发HTTP请求
- SpringBoot实现多数据源配置详解
- Java与MySQL的并发访问冲突:锁与事务
