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

jalse.actions.ForkJoinActionEngine Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
package jalse.actions;

import static jalse.actions.Actions.requireNotShutdown;
import static jalse.actions.Actions.requireNotStopped;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinPool.ManagedBlocker;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * An implementation of {@link ActionEngine} based on {@link ForkJoinPool}. Scheduling is achieved
 * using {@link ForkJoinPool#managedBlock(ManagedBlocker)} so many threads may be used but not all
 * executing {@link Action}.
*
* ForkJoinActionEngine offers an instance backed on {@link ForkJoinPool#commonPool()} that cannot * be stopped or paused ({@link #commonPoolEngine()}). * * @author Elliot Ford * */ public class ForkJoinActionEngine extends AbstractActionEngine { /** * Fork join context. * * @author Elliot Ford * * @param * Actor type. */ public class ForkJoinContext extends AbstractManualActionContext { /** * Creates a new ForkJoinContext. * * @param action * Action this context is for. */ protected ForkJoinContext(final Action action) { super(ForkJoinActionEngine.this, action, getBindings()); } @Override protected void addAsWork() { addWork(this); } @Override public void removeAsWork() { removeWork(this); } } private class ForkJoinContextWorker implements Runnable { private final ManagedBlocker blocker; private ForkJoinContextWorker() { blocker = new ManagedBlocker() { @Override public boolean block() throws InterruptedException { workQueue.awaitNextReadyWork(); return true; } @Override public boolean isReleasable() { return workQueue.isWorkReady() || !workQueue.isWorkWaiting(); } }; } @Override public void run() { while (workQueue.isWorkWaiting()) { try { awaitResumed(); // Paused } catch (final InterruptedException e) { break; } try { ForkJoinPool.managedBlock(blocker); // Allows other ForkJoinThreads to run } catch (final InterruptedException e) {} if (!workQueue.isWorkWaiting()) { break; } final ForkJoinContext work = workQueue.pollReadyWork(); if (work != null) { freeWorkers.decrementAndGet(); // Will be busy working try { work.performAction(); } catch (final InterruptedException e) { break; // Cancellation } finally { if (!freeWorkers.compareAndSet(0, 1)) { // Ready again return; } } } } freeWorkers.decrementAndGet(); // Finished. } } private static final ForkJoinActionEngine commonPoolEngine = new ForkJoinActionEngine(ForkJoinPool.commonPool()) { @Override public void pause() {}; @Override public void stop() {}; }; /** * Gets the common ForkJoinActionEngine instance backed by {@link ForkJoinPool#commonPool()} * (this cannot be paused or stopped). * * @return Common engine instance. */ public static ForkJoinActionEngine commonPoolEngine() { return commonPoolEngine; } private final ManualWorkQueue> workQueue; private final AtomicInteger freeWorkers; /** * Creates a new ForkJoinActionEngine instance with the default parallelism. * * @see Runtime#availableProcessors() */ public ForkJoinActionEngine() { this(Runtime.getRuntime().availableProcessors()); } private ForkJoinActionEngine(final ForkJoinPool pool) { super(pool); workQueue = new ManualWorkQueue<>(); freeWorkers = new AtomicInteger(); } /** * Creates a new ForkJoinActionEngine with the supplied parallelism. * * @param parallelism * The parallelism level. */ public ForkJoinActionEngine(final int parallelism) { this(new ForkJoinPool(parallelism)); } /** * Adds work to the engine. * * @param context * Work to add. * * @return Whether the work was not already in the queue. * * @see Actions#requireNotStopped(ActionEngine) */ protected boolean addWork(final ForkJoinContext context) { requireNotStopped(this); final boolean result; if (result = workQueue.addWaitingWork(context)) { addWorkerIfNeeded(); } return result; } /** * Starts a worker if needed (waiting work and no free workers). */ protected void addWorkerIfNeeded() { if (workQueue.isWorkWaiting() && freeWorkers.compareAndSet(0, 1)) { // Only needs one worker executorService.submit(new ForkJoinContextWorker()); } } /** * Gets the engine's work queue. * * @return Manual work queue. */ protected ManualWorkQueue> getWorkQueue() { return workQueue; } @Override public ForkJoinContext newContext(final Action action) { return new ForkJoinContext<>(action); } /** * Removes work from the engine. * * @param context * Work to remove. * @return Whether the work was added before. */ protected boolean removeWork(final ForkJoinContext context) { return workQueue.removeWaitingWork(context); } @Override public void stop() { requireNotShutdown(executorService); super.stop(); // Shutdown pool first workQueue.getWaitingWork().forEach(ForkJoinContext::cancel); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy