net.therore.concurrent.SelfTuningExecutorService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of therore-concurrent Show documentation
Show all versions of therore-concurrent Show documentation
Therore Concurrency Libraries are an expanded set of services and
types supporting advanced concurrent programming in Java.
The newest version!
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.therore.concurrent;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import net.therore.concurrent.SampleContainer.ExecutionState;
/**
* @author [email protected]
*/
public class SelfTuningExecutorService extends AbstractExecutorService implements ExecutorService, SelfTuningExecutorServiceMBean {
static public final long POLL_MSECS = 5000;
static public final int DEFAULT_POOLSIZE = 1;
private final ReentrantLock mainLock = new ReentrantLock();
static final int RUNNING = 0;
static final int SHUTDOWN = 1;
static final int STOP = 2;
static final int TERMINATED = 3;
private final String name;
private final SelfTuningExecutors executors;
private final ThreadPoolExecutor coreExecutorService;
private final SampleContainer sampleContainer;
private final ArrayBlockingQueue workQueue;
private final ParameterOptimizer optimizer;
private final AtomicInteger activeCount;
private final AtomicInteger totalExecutions;
private final int queueSize;
private final int initPoolSize;
private final int corePoolSize;
private final int maximumPoolSize;
private final int priority;
private volatile int poolSize = DEFAULT_POOLSIZE;
public SelfTuningExecutorService(SelfTuningExecutors executors, ThreadPoolExecutor coreExecutorService, String name
, int corePoolSize, int initPoolSize, int maximumPoolSize, int priority, int queueSize) {
this.name = name==null ? String.valueOf(System.identityHashCode(this)) : name;
this.executors = executors;
this.coreExecutorService = coreExecutorService;
this.sampleContainer = new SampleContainer(initPoolSize);
this.queueSize = queueSize;
this.workQueue = new ArrayBlockingQueue(queueSize, true);
this.activeCount = new AtomicInteger(0);
this.totalExecutions = new AtomicInteger(0);
this.initPoolSize = initPoolSize;
this.poolSize = initPoolSize;
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.priority = priority;
this.optimizer = new ParameterOptimizer(corePoolSize, maximumPoolSize, priority) {
public int getTotalPriority() {
return SelfTuningExecutorService.this.executors.getTotalPriority();
}
public int getTotalValue() {
return SelfTuningExecutorService.this.executors.getPoolSize();
}
};
}
@Override
public String getName() {
return name;
}
@Override
public int getQueueSize() {
return queueSize;
}
@Override
public int getInitPoolSize() {
return initPoolSize;
}
@Override
public int getCorePoolSize() {
return corePoolSize;
}
@Override
public int getMaximumPoolSize() {
return maximumPoolSize;
}
@Override
public int getPriority() {
return priority;
}
@Override
public int getPoolSize() {
return poolSize;
}
@Override
public double getThroughput() {
return sampleContainer.getThroughput();
}
@Override
public int getActiveCount() {
return activeCount.get();
}
@Override
public int getTotalExecutions() {
return totalExecutions.get();
}
public int getRunState() {
if (!coreExecutorService.isShutdown())
return RUNNING;
else if (coreExecutorService.isTerminated())
return TERMINATED;
else
return SHUTDOWN;
// NO STOP STATE
}
@Override
public void shutdown() {
coreExecutorService.shutdown();
}
@Override
public List shutdownNow() {
return coreExecutorService.shutdownNow();
}
@Override
public boolean isShutdown() {
return coreExecutorService.isShutdown();
}
@Override
public boolean isTerminated() {
return coreExecutorService.isTerminated();
}
@Override
public boolean isTerminating() {
return coreExecutorService.isTerminating();
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
return coreExecutorService.awaitTermination(timeout, unit);
}
@Override
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int runState = getRunState();
try {
while (!addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command, POLL_MSECS, TimeUnit.MILLISECONDS)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
break;
}
if (runState != RUNNING)
break;
}
} catch (InterruptedException e) {
reject(command);
}
}
void reject(Runnable command) {
coreExecutorService.getRejectedExecutionHandler().rejectedExecution(command, coreExecutorService);
}
private void addThread(Runnable firstTask) {
FlowControlWrapper w = new FlowControlWrapper(firstTask);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
activeCount.incrementAndGet();
} finally {
mainLock.unlock();
}
coreExecutorService.execute(w);
}
private boolean addIfUnderCorePoolSize(Runnable firstTask) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int runState = getRunState();
if (activeCount.get() < poolSize && runState == RUNNING) {
addThread(firstTask);
return true;
} else
return false;
} finally {
mainLock.unlock();
}
}
private void ensureQueuedTaskHandled(Runnable command) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
boolean reject = false;
try {
int state = getRunState();
if (state != RUNNING && workQueue.remove(command))
reject = true;
else if (state < STOP && activeCount.get() < poolSize &&
!workQueue.isEmpty())
addThread(null);
} finally {
mainLock.unlock();
}
if (reject)
reject(command);
}
protected Runnable getTask() {
for (;;) {
int state = getRunState();
Runnable r;
if (state == SHUTDOWN) // Help drain queue
r = workQueue.poll();
else if (activeCount.get() <= poolSize)
r = workQueue.poll();
else
r = null;
return r;
}
}
void workerDone(FlowControlWrapper w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (activeCount.decrementAndGet() == 0)
tryTerminate();
} finally {
mainLock.unlock();
}
}
private void tryTerminate() {
if (activeCount.get() == 0) {
int state = getRunState();
if (state < STOP && !workQueue.isEmpty()) {
state = RUNNING; // disable termination check below
addThread(null);
}
}
}
public class FlowControlWrapper implements Runnable {
private Runnable firstTask;
public FlowControlWrapper(Runnable firstTask) {
this.firstTask = firstTask;
}
/**
* Main run loop
*/
@Override
public void run() {
try {
Runnable task = firstTask;
firstTask = null;
while (task != null || (task = getTask()) != null) {
// annotate start execution
sampleContainer.annotationExecution(System.currentTimeMillis(), optimizer, ExecutionState.STARTED);
totalExecutions.incrementAndGet();
task.run();
task = null;
// annotate end execution
int tmpPoolSize = sampleContainer.annotationExecution(System.currentTimeMillis(), optimizer, ExecutionState.TERMINATED);
final ReentrantLock mainLock = SelfTuningExecutorService.this.mainLock;
mainLock.lock();
try {
poolSize = tmpPoolSize;
int count = activeCount.get();
if (count > tmpPoolSize)
break;
else if (count < tmpPoolSize)
addThread(null);
} finally {
mainLock.unlock();
}
}
} finally {
workerDone(this);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy