多线程的CountDownLatch的使用
前几天做分页的查询的时候,用多线程做了一下,总的条目数的查找,以及分页调用的程序。
@CrossOrigin(origins = "*",maxAge = 3600) @PostMapping(value="/GetTByCondition") public Map<String,Object> getIdModelPageList (@RequestBody ModelIdConditionInputDTO modelIdConditionInputDTO) { Map<String,Object> map = new HashMap<>(16); //CountDownLatch latch=new CountDownLatch(2); try { taskExecutor.execute(() -> { map.put("Tdto",idModelService.getPage(modelIdConditionInputDTO)); //latch.countDown(); }); taskExecutor.execute(() -> { map.put("RowCount",idModelService.getCount(modelIdConditionInputDTO)); //latch.countDown(); }); //latch.await(); json = this.setJson(200, GET_SUCESS, map); } catch (Exception e) { logger.error(e.getMessage()); } return json; }
返回结果
可以看到查到的是空值,根据bug调用,发现了问题。
首先
我定义的变量每次request的时候会自动为null,这个其实没什么。关键是下边二个
这二个service是要去数据库dao的。当我们request的时候,它直接去i/o,这过程需要时间。主线程也不管他直接返回给我个空值。
然后假如我再重新请求一次的话又会重复原来的结果。
我们试着把
Map<String,Object> map = new HashMap<>(16);
这段代码改一改看是不是复合我的猜想。
有意思的事情出现了,这是第一次request
这是第二次request
相信大家都已经看出端倪了。第一次request的时候,程序还没来得及取到数据(也就是那两次dao), 程序已经response了。导致返回的是空。第二次为啥有数据?第二次也是没来及插入数据的,那是第一次response以后,dao取出数据放在hashmap里的。也是说你第二次取的是第一次还没来得及返回的数据!!!因为我把hashmap定义为静态变量,所以会保存上次的值!!!我,们用CountDownLatch控制一下顺序。重启一下程序。
@CrossOrigin(origins = "*",maxAge = 3600) @PostMapping(value="/GetTByCondition") public Map<String,Object> getIdModelPageList (@RequestBody ModelIdConditionInputDTO modelIdConditionInputDTO) { Map<String,Object> map = new HashMap<>(16); CountDownLatch latch=new CountDownLatch(2); try { taskExecutor.execute(() -> { map.put("Tdto",idModelService.getPage(modelIdConditionInputDTO)); latch.countDown(); }); taskExecutor.execute(() -> { map.put("RowCount",idModelService.getCount(modelIdConditionInputDTO)); latch.countDown(); }); latch.await(); json = this.setJson(200, GET_SUCESS, map); } catch (Exception e) { logger.error(e.getMessage()); } return json; }
ok,结果和预期的一样。
其实这个bug挺有迷惑性的。我一开始还以为是赋值的错误,调试了半天。方向都没找对。当然最关键的是我对多线程的理解不够透彻,忽略了dao到数据库的时间差。