| /* |
| * Copyright 2015-2022 the original author or authors. |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License v2.0 which |
| * accompanies this distribution and is available at |
| * |
| * https://www.eclipse.org/legal/epl-v20.html |
| */ |
| |
| package org.junit.platform.commons.test; |
| |
| import static java.util.concurrent.TimeUnit.SECONDS; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.CompletableFuture; |
| import java.util.concurrent.CompletionException; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| |
| public class ConcurrencyTestingUtils { |
| |
| public static void executeConcurrently(int threads, Runnable action) throws Exception { |
| executeConcurrently(threads, () -> { |
| action.run(); |
| return null; |
| }); |
| } |
| |
| public static <T> List<T> executeConcurrently(int threads, Callable<T> action) throws Exception { |
| ExecutorService executorService = Executors.newFixedThreadPool(threads); |
| try { |
| CountDownLatch latch = new CountDownLatch(threads); |
| List<CompletableFuture<T>> futures = new ArrayList<>(); |
| for (int i = 0; i < threads; i++) { |
| futures.add(CompletableFuture.supplyAsync(() -> { |
| try { |
| latch.countDown(); |
| latch.await(); |
| return action.call(); |
| } |
| catch (InterruptedException e) { |
| Thread.currentThread().interrupt(); |
| throw new CompletionException(e); |
| } |
| catch (Exception e) { |
| throw new CompletionException("Action failed", e); |
| } |
| }, executorService)); |
| } |
| List<T> list = new ArrayList<>(); |
| for (CompletableFuture<T> future : futures) { |
| list.add(future.get(5, SECONDS)); |
| } |
| return list; |
| } |
| finally { |
| executorService.shutdownNow(); |
| var terminated = executorService.awaitTermination(5, SECONDS); |
| if (!terminated) { |
| //noinspection ThrowFromFinallyBlock |
| throw new AssertionError("ExecutorService did not cleanly shut down"); |
| } |
| } |
| } |
| } |