java阻塞主线程等待多个子线程执行完毕的解决方案 |
您所在的位置:网站首页 › 等待线程池里的线程全部执行完任务怎么办 › java阻塞主线程等待多个子线程执行完毕的解决方案 |
问题: 采用while(true)方式阻塞主线程,等待多个子线程执行完毕的方案。在系统负载升高时,存在while循环占用过多时间片,导致CPU被打满风险。 问题代码示例: final long start = System.currentTimeMillis(); while (true) { if (System.currentTimeMillis() - start >= 5 * MilliSecond.SECOND) { break; } if (futureList.parallelStream().allMatch(Future::isDone)) { break; } } /** * 等待全部线程完成(超时时间30s) * @param futureList List:future中装载线程内抛出的异常,线程正常结束则需要装载null */ public static void waitComplete(List futureList) throws Exception { final long start = System.currentTimeMillis(); while (true) { if (System.currentTimeMillis() - start >= 30 * MilliSecond.SECOND) { break; } if (futureList.stream().allMatch(Future::isDone)) { for (Future future : futureList) { if (future.get() != null) { throw future.get(); } } break; } } }解决方案: 建议使用java8提供的CompletableFuture,配合allof和join方法,阻塞主线程。 完整示例代码如下: package com.mark.utils.thread; import org.apache.commons.collections.CollectionUtils; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; /** * 线程相关工具类 * @author mark * @date 2022/9/8 10:58 */ @Component public class ThreadUtils { @Resource private ThreadPoolTaskExecutor commonTaskExecutor; @Resource private ThreadPoolTaskExecutor expensiveTaskExecutor; /** * 使用commonTaskExecutor线程池,开启新线程执行异步任务,新线程无返回值 */ public CompletableFuture commonTaskExecutorRun(Runnable runnable) { return CompletableFuture.runAsync(runnable, commonTaskExecutor); } /** * 使用commonTaskExecutor线程池,开启新线程执行异步任务,新线程有返回值 */ public CompletableFuture commonTaskExecutorSupply(Supplier supplier) { return CompletableFuture.supplyAsync(supplier, commonTaskExecutor); } /** * 使用expensiveTaskExecutor线程池,开启新线程执行异步任务,新线程无返回值 */ public CompletableFuture expensiveTaskExecutorRun(Runnable runnable) { return CompletableFuture.runAsync(runnable, expensiveTaskExecutor); } /** * 使用expensiveTaskExecutor线程池,开启新线程执行异步任务,新线程有返回值 */ public CompletableFuture expensiveTaskExecutorSupply(Supplier supplier) { return CompletableFuture.supplyAsync(supplier, expensiveTaskExecutor); } /** * 阻塞主线程,等待全部future执行完毕 */ public static void waitComplete(List futureList) { if (CollectionUtils.isEmpty(futureList)) { return; } CompletableFuture .allOf(futureList.toArray(new CompletableFuture[0])) .join(); } /** * 阻塞主线程,等待全部future执行完毕,线程返回的异常会被抛出 * @param futureList List:future中装载线程内抛出的异常,线程正常结束则需要装载null */ public static void waitCompleteThrow(List futureList) throws Exception { waitComplete(futureList); for (CompletableFuture future : futureList) { if (future.get() != null) { throw future.get(); } } } }CompletableFuture API: runAsync(Runnable runnable, Executor executor) 返回一个新的不携带返回值的CompletableFuture,使用指定的线程池执行任务。 supplyAsync(Supplier supplier, Executor executor) 返回一个新的携带返回值的CompletableFuture,使用指定的线程池执行任务。allOf(CompletableFuture… cfs) 返回一个新的CompletableFuture,当入参中所有CompletableFuture都执行完成后,它也会执行完成。 多个CompletableFuture独立执行,某个CompletableFuture抛出异常不会干扰其他。 get() throw InterruptedException, ExecutionException 阻塞当前线程,直到全部CompletableFuture执行完成,并拿到执行结果。 CompletableFuture执行过程中的异常会被抛出,进而结束掉主线程。此外,多个异常只有一个会被抛出。 该方法抛出checked异常。 join() 阻塞当前线程,直到全部CompletableFuture执行完成,并拿到执行结果。CompletableFuture执行过程中的异常会被抛出,进而结束掉主线程。此外,多个异常只有一个会被抛出。该方法返回unchecked异常,这是该方法和get()方法的主要区别。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |