
oracle.kv.impl.api.SharedThreadPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oracle-nosql-server Show documentation
Show all versions of oracle-nosql-server Show documentation
NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.
The newest version!
/*-
* Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle NoSQL
* Database made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle NoSQL Database for a copy of the license and
* additional information.
*/
package oracle.kv.impl.api;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
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;
import java.util.logging.Logger;
import oracle.kv.impl.api.KVStoreImpl.TaskExecutor;
import oracle.kv.impl.util.KVThreadFactory;
/**
* A shared thread pool which supports the submission and canceling of
* groups of tasks.
*/
public class SharedThreadPool {
private static final int KEEP_ALIVE_SEC = 10;
private final ThreadPoolExecutor threadPool;
/**
* Creates a shared thread pool.
*
* @param logger a logger passed to the thread factory
*/
public SharedThreadPool(Logger logger) {
/*
* With corePoolSize == 0 and maximumPoolSize == Integer.MAX_VALUE the
* thread pool is unbounded and will reuse an idle thread before
* creating a new one. Because the pool is unbounded a direct handoff
* queue is used. (see doc for ThreadPoolExecutor)
*
* Task submission will not be rejected unless the pool is shutdown.
*/
threadPool =
new ThreadPoolExecutor(0, // corePoolSize
Integer.MAX_VALUE, // maximumPoolSize
KEEP_ALIVE_SEC, TimeUnit.SECONDS,
new SynchronousQueue(),
new KVThreadFactory(" shared thread",
logger));
}
/**
* Gets a task executor instance. The returned executor will limit
* the number of concurrent tasks submitted to the shared thread pool to
* maxConcurrentTasks.
*
* @param maxConcurrentTasks the maximum number of concurrent tasks
* submitted to the thread pool
* @return a task executor instance
*/
public TaskExecutor getTaskExecutor(int maxConcurrentTasks) {
if (threadPool.isShutdown()) {
throw new IllegalStateException("The shared thread pool has been " +
"shutdown");
}
return new TaskExecutorImpl(maxConcurrentTasks);
}
/**
* Attempts to stop all actively executing tasks and halts the processing
* of waiting tasks. Subsequent calls to TaskExecutor.submit() will throw
* RejectedExecutionException.
*/
void shutdownNow() {
threadPool.shutdownNow();
}
/* -- For unit tests -- */
int getActiveCount() {
return threadPool.getActiveCount();
}
int getPoolSize() {
return threadPool.getPoolSize();
}
long getKeepAliveTime(TimeUnit timeUnit) {
return threadPool.getKeepAliveTime(timeUnit);
}
/**
* Implementation of a TaskExecutor which will submit tasks to the shared
* thread pool. It will queue tasks if necessary and will maintain handles
* to the tasks so that they may be canceled on shutdown.
*/
private class TaskExecutorImpl implements TaskExecutor {
private final int maxConcurrentTasks;
private final Queue taskQueue;
private final Set runningTasks;
private volatile boolean closed = false;
private TaskExecutorImpl(int maxConcurrentTasks) {
this.maxConcurrentTasks = maxConcurrentTasks;
taskQueue = new LinkedBlockingQueue();
runningTasks = new HashSet(maxConcurrentTasks);
}
@Override
public synchronized Future> submit(Runnable r) {
if (closed) {
throw new RejectedExecutionException();
}
final WrappedTask task = new WrappedTask(r, this);
if (runningTasks.size() >= maxConcurrentTasks) {
taskQueue.add(task);
} else {
submitWrappedTask(task);
}
return task;
}
@Override
public List shutdownNow() {
closed = true;
synchronized (this) {
for (WrappedTask task : runningTasks) {
task.cancel(true);
}
ArrayList ret = new ArrayList(taskQueue);
taskQueue.clear();
return ret;
}
}
/*
* Processes a completed task. The specified task is removed from
* the running task list and if allowed a new task is submitted
* to the pool.
*/
private synchronized void completed(WrappedTask task) {
if (closed) {
return;
}
runningTasks.remove(task);
while (!closed && !taskQueue.isEmpty() &&
(runningTasks.size() < maxConcurrentTasks)) {
submitWrappedTask(taskQueue.remove());
}
}
/*
* Submits a task to be executed. If the task cannot be immediately
* added to the shared thread pool it is queued to be submitted
* at a later time.
*/
private void submitWrappedTask(WrappedTask task) {
assert Thread.holdsLock(this);
try {
threadPool.execute(task);
runningTasks.add(task);
} catch (RejectedExecutionException ree) {
/* Should only happen if the pool is shutdown */
if (threadPool.isShutdown()) {
closed = true;
throw ree;
}
throw new IllegalStateException("Unexpected task rejection",
ree);
}
}
@Override
public String toString() {
return "TaskExecutor[max=" + maxConcurrentTasks + ",running=" +
runningTasks.size() + ",queue=" + taskQueue.size() +
",pool=" + threadPool.getPoolSize() + "]";
}
}
/**
* Wrapper for tasks submitted to the shared thread pool. This wrapper
* allows the task executor to be notified when the task is done and also
* serves as the task's future.
*/
private static class WrappedTask extends FutureTask
© 2015 - 2025 Weber Informatics LLC | Privacy Policy