public static CloseableExecutor of(ExecutorService executor) { return new CloseableExecutor(executor); } }
public static Parallel blocking(int threads, IntConsumer r) { return create(threads, BLOCKING, r); }
private static Parallel create(int threads, boolean blocking, IntConsumer r) { final CountDownLatch latch = blocking ? new CountDownLatch(threads) : null; final CyclicBarrier barrier = new CyclicBarrier(threads + 1); final String threadNameFormat = "ParRunner-%0" + numDigits(threads) + "d"; for (int i = 0; i < threads; i++) { final int _i = i; final Thread t = new Thread(() -> { Threads.await(barrier); try { r.accept(_i); } finally { if (latch != null) latch.countDown(); } }, String.format(threadNameFormat, i)); t.start(); } return new Parallel(latch, barrier); }
public static boolean await(CyclicBarrier barrier) { return runUninterruptedly(() -> { try { barrier.await(); } catch (BrokenBarrierException e) { throw new RuntimeBrokenBarrierException(e); } }); }
private static <T> Parallel slice(List<T> list, int threads, boolean blocking, Consumer<List<T>> task) { final int actualThreads = Math.min(threads, list.size()); final List<List<T>> lists = split(list, actualThreads); return create(actualThreads, blocking, i -> { final List<T> sublist = lists.get(i); task.accept(sublist); }); }
public static <T> Parallel blockingSlice(List<T> list, int threads, Consumer<List<T>> task) { return slice(list, threads, BLOCKING, task); }
public static boolean await(CountDownLatch latch) { return runUninterruptedly(latch::await); }
public <T, X extends Throwable> T run(CheckedSupplier<? extends T, X> operation) throws X { for (int attempt = 0;; attempt++) { try { return operation.get(); } catch (Throwable e) { if (exceptionMatcher.test(e)) { if (attempt == attempts - 1) { final String faultMessage = String.format("Fault (attempt #%,d of %,d): aborting", attempt + 1, attempts); errorHandler.onException(faultMessage, e); throw e; } else { final String retryMessage = String.format("Fault (attempt #%,d of %,d): retrying in %,d ms", attempt + 1, attempts, backoffMillis); faultHandler.onException(retryMessage, e); if (! Threads.sleep(backoffMillis)) { final String interruptMessage = String.format("Fault (attempt #%,d of %,d): aborting due to interrupt", attempt + 1, attempts); errorHandler.onException(interruptMessage, e); throw e; } } } else { throw e; } } } } }
public static Parallel nonBlocking(int threads, IntConsumer r) { return create(threads, NON_BLOCKING, r); }
public static <T> Parallel nonBlockingSlice(List<T> list, int threads, Consumer<List<T>> task) { return slice(list, threads, NON_BLOCKING, task); }
public static boolean sleep(long millis) { if (millis > 0) { return runUninterruptedly(() -> Thread.sleep(millis)); } else { return ! Thread.currentThread().isInterrupted(); } }