/******************************************************************************
* Copyright © 2013-2016 The Nxt Core Developers. *
* *
* See the AUTHORS.txt, DEVELOPER-AGREEMENT.txt and LICENSE.txt files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* Nxt software, including this file, may be copied, modified, propagated, *
* or distributed except according to the terms contained in the LICENSE.txt *
* file. *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
package nxt.util;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* QueuedThreadPool creates threads to process requests until the maximum pool
* size is reached. Additional requests are queued until a thread becomes
* available. Threads that are idle for 60 seconds are terminated if the
* pool size is greater than the core size.
*/
public class QueuedThreadPool extends ThreadPoolExecutor {
/** Core pool size */
private int coreSize;
/** Maximum pool size */
private int maxSize;
/** Pending task queue */
private final LinkedBlockingQueue<Runnable> pendingQueue = new LinkedBlockingQueue<>();
/**
* Create the queued thread pool
*
* @param coreSize Core pool size
* @param maxSize Maximum pool size
*/
public QueuedThreadPool(int coreSize, int maxSize) {
super(coreSize, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
this.coreSize = coreSize;
this.maxSize = maxSize;
}
/**
* Return the core pool size
*
* @return Core pool size
*/
@Override
public int getCorePoolSize() {
return coreSize;
}
/**
* Set the core pool size
*
* @param coreSize Core pool size
*/
@Override
public void setCorePoolSize(int coreSize) {
super.setCorePoolSize(coreSize);
this.coreSize = coreSize;
}
/**
* Return the maximum pool size
*
* @return Maximum pool size
*/
@Override
public int getMaximumPoolSize() {
return maxSize;
}
/**
* Set the maximum pool size
*
* @param maxSize Maximum pool size
*/
@Override
public void setMaximumPoolSize(int maxSize) {
this.maxSize = maxSize;
}
/**
* Execute a task
*
* @param task Task
* @throws RejectedExecutionException Unable to execute task
*/
@Override
public void execute(Runnable task) throws RejectedExecutionException {
if (task == null)
throw new NullPointerException("Null runnable passed to execute()");
try {
if (getActiveCount() >= maxSize) {
pendingQueue.put(task);
} else {
super.execute(task);
}
} catch (InterruptedException exc) {
throw new RejectedExecutionException("Unable to queue task", exc);
}
}
/**
* Submit a task for execution
*
* @param task Runnable task
* @return Future representing the task
* @throws RejectedExecutionException Unable to execute task
*/
@Override
public Future<?> submit(Runnable task) throws RejectedExecutionException {
if (task == null)
throw new NullPointerException("Null runnable passed to submit()");
FutureTask<Void> futureTask = new FutureTask<>(task, null);
execute(futureTask);
return futureTask;
}
/**
* Submit a task for execution
*
* @param <T> Result type
* @param task Runnable task
* @param result Result returned when task completes
* @return Future representing the task result
* @throws RejectedExecutionException Unable to execute task
*/
@Override
public <T> Future<T> submit(Runnable task, T result) throws RejectedExecutionException {
if (task == null)
throw new NullPointerException("Null runnable passed to submit()");
FutureTask<T> futureTask = new FutureTask<>(task, result);
execute(futureTask);
return futureTask;
}
/**
* Submit a task for execution
*
* @param <T> Result type
* @param callable Callable task
* @return Future representing the task
* @throws RejectedExecutionException Unable to execute task
*/
@Override
public <T> Future<T> submit(Callable<T> callable) throws RejectedExecutionException {
if (callable == null)
throw new NullPointerException("Null callable passed to submit()");
FutureTask<T> futureTask = new FutureTask<>(callable);
execute(futureTask);
return futureTask;
}
/**
* Process task completion
*
* @param task Runnable task
* @param exc Thrown exception
*/
@Override
protected void afterExecute(Runnable task, Throwable exc) {
super.afterExecute(task, exc);
Runnable newTask = pendingQueue.poll();
if (newTask != null)
super.execute(newTask);
}
}