现状
有一个跑批业务(几年前的代码了),现在业务提出需求,要对这个跑批里的一种场景做特殊处理,特殊体现在 业务逻辑特殊、跑批频次特殊,因此不好在原跑批里进行杂糅,为此我抽出该特殊场景做单独跑批,该特殊场景和原跑批做绝对隔离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @XxlJob("xxxHandler") public ReturnT<string> xxxHandler(String param) { List<String> ids = getIds(); CountDownLatch cdl = new CountDownLatch(ids.size()); for (string id : ids) { executor.execute(() -> { dealBiz(id,cdl); }); } cdl.await(); log.info("执行耗时-->{}",耗时); return ReturnT.SUCCESS; }
private void dealBiz(String id, CountDownLatch cdl){ ... cdl.countDown(); }
|
对原逻辑修改 v1版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @XxlJob("xxxHandler") public Returnt<string> xxxHandler(String param) { List<string> ids = getids(); CountDownLatch cdl = new CountDownLatch(ids.size()); for (String id : ids) { if (isSpecialBiz(id)) { continue; } executor.execute(() -> { dealBiz(id,cdl); }); } cdl.await(); log.info("执行耗时-->{}",耗时) return ReturnT.SUCCESS; }
private void dealBiz(String id, CountDownLatch cdl){ ... cdl.countDown(); }
|
问题
发现问题没?跳过特殊场景的逻辑并没有做countDown()操作,这将会导致这样的情况发生:如果getIds()获得的ids存在特殊场景件,由于跳过时没有countDown(),所以cdl永远不会为0,也就是一直会await()阻塞着。随着时间的推移,await()的线程越来越多,终会oom。
测试环境因为间隔几个小时会自动启动,再加上特殊场景的件不多,且原跑批的频率不高,这个问题在测试阶段并未出现。幸好,上线前发现并修复了。
修复方法
跳过特殊场景时加入 cdl.countDown()
1 2 3 4
| if (isSpecialBiz(id)) { cdl.countDown(); continue; }
|
总结
疏忽了!下次遇到CountDownLatch要千万注意!