com.mindsnacks.zinc.classes.downloads.PriorityJobQueue Maven / Gradle / Ivy
package com.mindsnacks.zinc.classes.downloads;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.mindsnacks.zinc.exceptions.ZincRuntimeException;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* User: NachoSoto
* Date: 9/21/13
*/
public class PriorityJobQueue {
private static final int INITIAL_QUEUE_CAPACITY = 20;
private static final int SCHEDULER_TERMINATION_TIMEOUT = 30;
private static final int EXECUTOR_SERVICE_TERMINATION_TIMEOUT = 300;
private static final int FUTURE_WAITING_SECONDS_INTERVAL = 2;
private final int mConcurrency;
private final ThreadFactory mThreadFactory;
private final DataProcessor mDataProcessor;
private final PriorityCalculator mPriorityCalculator;
private ExecutorService mScheduler;
private ListeningExecutorService mExecutorService;
private ListeningExecutorService mFuturesExecutorService;
private final SortablePriorityBlockingQueue mQueue;
private final Map> mFutures = new HashMap>();
private final Set mAddedElements = new HashSet();
private final Lock mLock = new ReentrantLock();
private final Condition mEnqueued = mLock.newCondition();
private final Semaphore mEnqueuedDataSemaphore;
private final AtomicBoolean mShouldReorder = new AtomicBoolean(false);
public PriorityJobQueue(final int concurrency,
final ThreadFactory threadFactory,
final PriorityCalculator priorityCalculator,
final DataProcessor dataProcessor) {
mConcurrency = concurrency;
mThreadFactory = threadFactory;
mDataProcessor = dataProcessor;
mEnqueuedDataSemaphore = new Semaphore(concurrency);
mPriorityCalculator = priorityCalculator;
mQueue = new SortablePriorityBlockingQueue(new PriorityBlockingQueue(INITIAL_QUEUE_CAPACITY, createPriorityComparator(mPriorityCalculator)));
}
public boolean isRunning() {
return (mScheduler != null || mExecutorService != null);
}
public synchronized void start() {
checkServiceIsRunning(false, "Service is already running");
mScheduler = Executors.newSingleThreadExecutor(mThreadFactory);
mFuturesExecutorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool(mThreadFactory));
mExecutorService = MoreExecutors.listeningDecorator(new ThreadPoolExecutor(
mConcurrency,
mConcurrency,
0L, TimeUnit.MICROSECONDS,
new LinkedBlockingQueue(),
mThreadFactory) {
@Override
protected void afterExecute(final Runnable r, final Throwable t) {
super.afterExecute(r, t);
mEnqueuedDataSemaphore.release();
}
});
mScheduler.submit(createSchedulerTask());
}
private Comparator createPriorityComparator(final PriorityCalculator priorityCalculator) {
final Comparator comparator = DownloadPriority.createComparator();
return new Comparator() {
@Override
public int compare(final Input o1, final Input o2) {
return comparator.compare(
priorityCalculator.getPriorityForObject(o1),
priorityCalculator.getPriorityForObject(o2));
}
};
}
public synchronized boolean stop() throws InterruptedException {
checkServiceIsRunning(true, "Service is already stopped");
boolean stopped = false;
mScheduler.shutdownNow();
stopped = mScheduler.awaitTermination(SCHEDULER_TERMINATION_TIMEOUT, TimeUnit.SECONDS);
mExecutorService.shutdown();
stopped &= mExecutorService.awaitTermination(EXECUTOR_SERVICE_TERMINATION_TIMEOUT, TimeUnit.SECONDS);
mFuturesExecutorService.shutdown();
stopped &= mFuturesExecutorService.awaitTermination(EXECUTOR_SERVICE_TERMINATION_TIMEOUT, TimeUnit.SECONDS);
if (stopped) {
mScheduler = mExecutorService = mFuturesExecutorService = null;
}
return stopped;
}
public void add(final Input element) {
mLock.lock();
try {
mAddedElements.add(element);
mQueue.offer(element);
} finally {
mLock.unlock();
}
}
public Future
© 2015 - 2024 Weber Informatics LLC | Privacy Policy