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

uk.co.codera.lang.concurrent.SequencedPriorityExecutor Maven / Gradle / Ivy

The newest version!
package uk.co.codera.lang.concurrent;

import java.util.Comparator;
import java.util.concurrent.Executor;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 

* An implementation of the {@link Executor} that is backed by a * {@link PriorityBlockingQueue}. *

*

* One drawback of the backing queue is jobs with equal priority are not * guaranteed to be run in any particular order. This implementation ensures * they are run in the order submitted by assigning a sequence number when the * job is offered for execution. This is then used in conjunction with the * priority to determine which task should be executed next. *

* * @author andystewart */ public class SequencedPriorityExecutor implements Executor { public static final int INITIAL_QUEUE_CAPACITY = 1000; private static final int SINGLE_THREAD = 1; private final Executor underlyingExecutor; private final AtomicLong sequenceNumber; private SequencedPriorityExecutor(int numberThreads, Comparator comparator) { this.underlyingExecutor = threadPoolExecutor(numberThreads, comparator); this.sequenceNumber = new AtomicLong(0); } public static Executor singleThreadedExecutor(Comparator comparator) { return new SequencedPriorityExecutor(SINGLE_THREAD, comparator); } @Override public void execute(Runnable command) { SequencedRunnable sequencedCommand = new SequencedRunnable(command, this.sequenceNumber.getAndIncrement()); this.underlyingExecutor.execute(sequencedCommand); } private ThreadPoolExecutor threadPoolExecutor(int numberThreads, Comparator comparator) { return new ThreadPoolExecutor(numberThreads, numberThreads, 0L, TimeUnit.MILLISECONDS, blockingQueue(comparator)); } private PriorityBlockingQueue blockingQueue(Comparator comparator) { return new PriorityBlockingQueue<>(INITIAL_QUEUE_CAPACITY, new SequencedPriorityComparator(comparator)); } private static class SequencedRunnable implements Runnable { private final Runnable underlyingRunnable; private final Long sequenceNumber; private SequencedRunnable(Runnable command, long sequenceNumber) { this.underlyingRunnable = command; this.sequenceNumber = Long.valueOf(sequenceNumber); } @SuppressWarnings("squid:S1217") @Override public void run() { this.underlyingRunnable.run(); } public Long getSequenceNumber() { return sequenceNumber; } public Runnable getUnderlyingRunnable() { return this.underlyingRunnable; } } private static class SequencedPriorityComparator implements Comparator { private final Comparator priorityComparator; private SequencedPriorityComparator(Comparator priorityComparator) { this.priorityComparator = priorityComparator; } @Override public int compare(Runnable o1, Runnable o2) { SequencedRunnable s1 = (SequencedRunnable) o1; SequencedRunnable s2 = (SequencedRunnable) o2; int priority = this.priorityComparator.compare(s1.getUnderlyingRunnable(), s2.getUnderlyingRunnable()); if (priority == 0) { return s1.getSequenceNumber().compareTo(s2.getSequenceNumber()); } return priority; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy