/*******************************************************************************
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* All rights reserved. This program and the accompanying materials are made available under
* the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package gov.redhawk.sca.model.provider.refresh.internal;
import gov.redhawk.sca.model.provider.refresh.RefreshProviderPlugin;
import gov.redhawk.sca.util.Debug;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
*
*/
public class StarvationThreadPoolExecutor extends ThreadPoolExecutor {
private static final Debug DEBUG = new Debug(RefreshProviderPlugin.PLUGIN_ID, "worker");
private static final int MIN_POOL = 5;
private class Task implements Runnable {
private long startTime = -1;
private final Runnable command;
public Task(Runnable command) {
this.command = command;
}
public boolean isRunning() {
return startTime > 0;
}
public boolean isHanging() {
return isRunning() && (System.currentTimeMillis() - startTime > RefreshProviderPlugin.getRefreshTimeout());
}
@Override
public void run() {
startTime = System.currentTimeMillis();
try {
command.run();
} finally {
tasks.remove(this);
fixPoolSize();
}
}
}
private final List<Task> tasks = Collections.synchronizedList(new LinkedList<StarvationThreadPoolExecutor.Task>());
public StarvationThreadPoolExecutor(ThreadFactory factory) {
super(0, MIN_POOL, 2, TimeUnit.MINUTES, new SynchronousQueue<Runnable>(), factory);
allowCoreThreadTimeOut(true);
}
private void fixPoolSize() {
synchronized (tasks) {
int numHanging = 0;
for (Task t : tasks) {
if (t.isHanging()) {
numHanging++;
}
}
int adjustedMinPool = MIN_POOL + numHanging;
int currentMax = getMaximumPoolSize();
int newMax = (adjustedMinPool / 5 + 1) * 5;
boolean adjust = false;
if (numHanging == 0) {
adjust = true;
newMax = MIN_POOL;
} else if (numHanging > 0) {
if (currentMax < newMax) {
adjust = true;
} else if (newMax >= adjustedMinPool + 5) {
adjust = true;
}
}
if (adjust && newMax != currentMax) {
setMaximumPoolSize(newMax);
if (DEBUG.enabled) {
DEBUG.message("Adjusting pool size to: " + newMax + " old max = " + currentMax + " adjusted min = " + adjustedMinPool);
}
}
}
}
@Override
public void shutdown() {
tasks.clear();
super.shutdown();
}
@Override
public List<Runnable> shutdownNow() {
tasks.clear();
return super.shutdownNow();
}
@Override
public void execute(Runnable command) {
Task task = new Task(command);
fixPoolSize();
tasks.add(task);
super.execute(task);
}
}