[Java线程] CountDownLatch使用
CountDownLatch可以用来让一个或多个线程等待,如下代码所示:
public class TestCountDownLatch { public static void main(String[] args) { CountDownLatch countDownLatch = new CountDownLatch(2); Long start = System.currentTimeMillis(); System.out.println(String.format("Thread: %s start: %d", Thread.currentThread(), start)); ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(new Handler(countDownLatch)); executorService.submit(new Handler(countDownLatch)); try { if(!countDownLatch.await(2000, TimeUnit.MILLISECONDS)){ System.out.println(String.format("Thread: %s time elapses: %d", Thread.currentThread(), System.currentTimeMillis() - start)); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(String.format("Thread: %s duration: %d", Thread.currentThread(), System.currentTimeMillis() - start)); } static class Handler implements Runnable{ CountDownLatch countDownLatch; Handler(CountDownLatch countDownLatch){ this.countDownLatch = countDownLatch; } @Override public void run() { long start = System.currentTimeMillis(); System.out.println(String.format("Thread: %s start: %d", Thread.currentThread(), start)); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(String.format("Thread: %s duration: %d", Thread.currentThread(), System.currentTimeMillis() - start)); countDownLatch.countDown(); } } }
结果输出:
Thread: Thread[main,5,main] start: 1553483802605 Thread: Thread[pool-1-thread-1,5,main] start: 1553483802634 Thread: Thread[pool-1-thread-2,5,main] start: 1553483802634 Thread: Thread[main,5,main] time elapses: 2033 Thread: Thread[main,5,main] duration: 2033 Thread: Thread[pool-1-thread-2,5,main] duration: 5002 Thread: Thread[pool-1-thread-1,5,main] duration: 5002
实际使用过程中,可以用来控制多个线程等待,CountdownLatch作为结束等待信号。比如说我有一个任务,可以拆分成多个子任务并行执行,最后将执行结果汇总,如下是我在实际生产环境用的代码,一个人有多个联系人电话,我需要拿到每个电话关联的信息,最后汇总在一起,如下代码所示:
CountDownLatch latch = new CountDownLatch(mobile.size()) //mobile是电话数组,每个电话号码都单独处理 mobile.each {m -> CompletableFuture.supplyAsync({ //add log String notifyId = null try{ ValidateService validateService = getValidateService() String modelid = String.valueOf(attributes.get("modelid")) AddLogVO vo = new AddLogVO() vo.setAppid(_notification.getAppid()) vo.setDatatype("online.forecastscore.v3") vo.setSource("mq-service") vo.setTaskId(_notification.getTaskid()) vo.setClientAppKey(_notification.getClientappkey()) vo.setKeyword(String.valueOf(m.value) + modelid.substring(modelid.length()-1)) vo.setQueryParams(String.valueOf(m.value)) notifyId = validateService.addLog(vo) }catch (Exception ex){ logger.warn(String.format("Create log failure ex: %s", ex.getMessage()), ex) } def _notification = JSON.parseObject(JSON.toJSONString(notification),PullDataNotification.class) _notification.notifyId = notifyId _notification.datatype = "online.forecastscore.v3" _notification.attributes.mobile = m.value _notification.attributes.contactType = m.key pullNotificationService.dispatchNotification(_notification) //每个电话号码都去拉取数据 }).thenApply({ latch.countDown() // }) } //如果等待10秒发现还没有结束 if(!latch.await(3000, TimeUnit.MILLISECONDS)){ //为了防止无限等待,设置超时时间 logger.warn(String.format("user3rd.forecastscore.v3 run timeout...")) status = 2 }
注意上面的 latch.await() 方法,为了防止无限等待子线程,设置超时时间。
欢迎关注Java流水账公众号