先看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| CountDownLatch countDownLatch = new CountDownLatch(params.size()); try { params.forEach(regionNameMapping -> { CompletableFuture.runAsync(() -> { Region region = this.getRegionById(regionNameMapping.getRegionId()); regionNameMapping.getRegionNameConsumer().accept(region.getName()); countDownLatch.countDown(); }); }); countDownLatch.await(); } catch (Exception e) { log.error(e.getMessage(), e); }
|
上面的代码逻辑很简单,并发去执行getRegionById这个方法。然后await等待结果。
但是里面有一个隐患,当region查出来为null时,会出现NPE,就会导致countDown()无法被执行,于是程序就一直阻塞在
1 2
| countDownLatch.await();
|
正确的写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| CountDownLatch countDownLatch = new CountDownLatch(params.size()); try { params.forEach(regionNameMapping -> { CompletableFuture.runAsync(() -> { try{ Region region = this.getRegionById(regionNameMapping.getRegionId()); regionNameMapping.getRegionNameConsumer().accept(region.getName()); }finally{ countDownLatch.countDown(); } }); }); countDownLatch.await(3,TimeUnit.SECONDS); } catch (Exception e) { log.error(e.getMessage(), e); }
|
添加try、finally,保证最终锁会被释放,以及设置等待超时时间,避免程序挂掉。
所有使用AbstractQueuedSynchronizer实现的同步器,例如Lock,Semaphore、等都应该如此。