package com.arondor.common.management.threadpool;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import org.apache.log4j.Logger;
/**
* Scheduled Thread Factory with timeout monitoring
*/
public class MonitoredScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor
{
private static final Logger LOG = Logger.getLogger(MonitoredScheduledThreadPoolExecutor.class);
public MonitoredScheduledThreadPoolExecutor(int corePoolSize)
{
super(corePoolSize);
}
public MonitoredScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler)
{
super(corePoolSize, handler);
}
public MonitoredScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory)
{
super(corePoolSize, threadFactory);
}
public MonitoredScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
{
super(corePoolSize, threadFactory, handler);
}
private int timeout = 0;
public int getTimeout()
{
return timeout;
}
public void setTimeout(int timeout)
{
this.timeout = timeout;
startTaskMonitoring();
}
private Thread taskMonitoringThread = null;
protected synchronized void startTaskMonitoring()
{
if (taskMonitoringThread != null)
{
return;
}
taskMonitoringThread = new Thread()
{
@Override
public void run()
{
doMonitorLoop();
}
};
taskMonitoringThread.setDaemon(true);
taskMonitoringThread.start();
}
protected void doMonitorLoop()
{
while (true)
{
if (isTerminated())
{
LOG.info("Stopping monitor : shutdown !");
return;
}
doMonitor();
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
}
}
}
private synchronized void doMonitor()
{
for (Map.Entry<Thread, Long> threadStartEntry : runningThreads.entrySet())
{
Long startTime = threadStartEntry.getValue();
if (startTime == null)
{
continue;
}
long now = System.currentTimeMillis();
if (now - startTime >= timeout)
{
Thread th = threadStartEntry.getKey();
LOG.info("Thread " + threadName(th) + " is timedout !");
try
{
th.interrupt();
}
catch (SecurityException e)
{
LOG.error("Could not interrupt !", e);
}
}
}
}
private final Map<Thread, Long> runningThreads = new HashMap<Thread, Long>();
private static final String threadName(Thread th)
{
return th.getName() + " [id:" + th.getId() + "]";
}
protected synchronized void setTaskStart()
{
Thread th = Thread.currentThread();
if (runningThreads.get(th) != null)
{
LOG.error("Thread " + threadName(th) + " has an unfinished task !");
throw new IllegalStateException("Thread " + threadName(th) + " has an unfinished task !");
}
LOG.info("Thread : " + threadName(th) + ", Task Start");
runningThreads.put(th, System.currentTimeMillis());
}
protected synchronized void setTaskEnd()
{
Thread th = Thread.currentThread();
LOG.info("Thread : " + threadName(th) + ", Task End");
if (runningThreads.get(th) == null)
{
LOG.error("Thread " + threadName(th) + " was not declared as running !");
}
runningThreads.remove(th);
}
private Runnable decorateRunnable(final Runnable task)
{
return new Runnable()
{
public void run()
{
LOG.debug("Decorate runnable " + task);
try
{
setTaskStart();
task.run();
}
finally
{
setTaskEnd();
}
}
};
}
private <T> Callable<T> decorateCallable(final Callable<T> task)
{
return new Callable<T>()
{
public T call() throws Exception
{
LOG.debug("Decorate callable " + task);
try
{
setTaskStart();
return task.call();
}
finally
{
setTaskEnd();
}
}
};
}
@Override
public <T> Future<T> submit(Callable<T> task)
{
return super.submit(task);
}
@Override
public Future<?> submit(Runnable task)
{
return super.submit(decorateRunnable(task));
}
@Override
public <T> Future<T> submit(Runnable task, T result)
{
return super.submit(decorateRunnable(task), result);
}
}