All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.team33.patterns.testing.titan.Parallel Maven / Gradle / Ivy

There is a newer version: 1.19.2
Show newest version
package de.team33.patterns.testing.titan;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.toList;

/**
 * A tool/utility used to perform a given operation multiple times in parallel threads, with a fixed number
 * of executing threads. Each thread performs the operation at least once and repeats it until all intended
 * threads have effectively started.
 * 

* The operation is given unique context information each time it is executed, showing an assignment to the * executing thread, the absolute start order, and repetition within the executing thread. */ public final class Parallel { private final Report.Builder report = new Report.Builder<>(); private final AtomicInteger threadCounter = new AtomicInteger(0); private final AtomicInteger operationCounter = new AtomicInteger(0); private final List threads; private Parallel(final int numberOfThreads, final Operation operation) { this.threads = unmodifiableList(IntStream.range(0, numberOfThreads) .mapToObj(threadIndex -> newThread(threadIndex, operation)) .collect(toList())); } /** * Returns a {@link Report} after executing a particular operation multiple times in parallel. *

* The operation is executed at least once by each of the designated threads and is repeated until all threads * have actually started. * * @param numberOfThreads The number of parallel threads in which the operation should be performed. * @param operation The operation to be performed. * @param The type of result of the operation to be performed. */ public static Report report(final int numberOfThreads, final Operation operation) { return new Parallel(numberOfThreads, operation).startThreads() .joinThreads() .report(); } /** * Returns a {@link Stream} of results after executing a particular operation multiple times in parallel. *

* The operation is executed at least once by each of the designated threads and is repeated until all threads * have actually started. * * @param numberOfThreads The number of parallel threads in which the operation should be performed. * @param operation The operation to be performed. * @param The type of result of the operation to be performed. * @throws Exception If any Exception occurs while executing the Operation */ @SuppressWarnings("ProhibitedExceptionDeclared") public static Stream stream(final int numberOfThreads, final Operation operation) throws Exception { return report(numberOfThreads, operation).reThrow(Error.class) .reThrow(Exception.class) .stream(); } private Thread newThread(final int threadIndex, final Operation operation) { //noinspection ObjectToString return new Thread(newRunnable(operation), this + ":" + threadIndex); } @SuppressWarnings({"BoundedWildcard", "OverlyBroadCatchBlock"}) private Runnable newRunnable(final Operation operation) { return () -> { final int threadIndex = threadCounter.getAndIncrement(); for (int loop = 0; (loop == 0) || (threadCounter.get() < threads.size()); ++loop) { try { report.add(operation.operate(new Context(threadIndex, operationCounter.getAndIncrement(), loop))); } catch (final Throwable e) { report.add(e); } } }; } private Parallel startThreads() { for (final Thread thread : threads) { thread.start(); } return this; } private Parallel joinThreads() { for (final Thread thread : threads) { try { thread.join(); } catch (final InterruptedException caught) { Thread.currentThread().interrupt(); report.add(caught); } } return this; } private Report report() { return report.build(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy