package jadex.commons.concurrent;
import jadex.commons.SReflect;
import jadex.commons.collection.ArrayBlockingQueue;
import jadex.commons.collection.IBlockingQueue;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
/**
* A thread pool manages pool and saves resources
* and time by precreating and reusing pool.
*/
public class ThreadPool implements IThreadPool
{
//-------- constants --------
/** The thread number. */
protected static int threadcnt = 0;
/** The static thread pool number. */
protected static int poolcnt = 0;
//-------- attributes --------
/** The thread group. */
protected ThreadGroup group;
/** The strategy. */
protected IThreadPoolStrategy strategy;
/** The pool of service threads. */
protected List pool;
/** The tasks to execute. */
// Todo: fix blocking queue.
protected IBlockingQueue tasks;
// protected BlockingQueue tasks;
/** The running flag. */
protected boolean running;
/** The task - thread mapping. */
protected Map threads;
//-------- constructors --------
/**
* Create a new thread pool.
*/
public ThreadPool()
{
this(new DefaultThreadPoolStrategy(0, 20, 30000, 0));
}
/**
* Create a new thread pool.
*/
public ThreadPool(IThreadPoolStrategy strategy)
{
this.strategy = strategy;
this.group = new ThreadGroup("strategy_thread_pool_"+poolcnt++);
this.running = true;
this.tasks = new ArrayBlockingQueue();
// this.tasks = new java.util.concurrent.LinkedBlockingQueue();
this.pool = new ArrayList();
this.threads = new Hashtable();
addThreads(strategy.getThreadCount());
// System.out.println("Creating: "+this);
}
//-------- methods --------
/**
* Execute a task in its own thread.
* @param task The task to execute.
*/
public synchronized void execute(Runnable task)
{
if(!running)
throw new RuntimeException("Thread pool not running: "+this);
if(this.strategy.taskAdded())
addThreads(1);
this.tasks.enqueue(task);
// this.tasks.add(task);
}
/**
* Shutdown the task pool
*/
public synchronized void dispose()
{
this.running = false;
this.tasks.setClosed(true);
// Todo: kill threads that don't terminate?
// How to find zombies???
// What about the current thread?
// Thread.yield();
// for(int i=0; i<pool.size(); i++) // Hack!!! Kill all threads.
// {
// Thread t = (Thread)pool.get(i);
// if(!t.equals(Thread.currentThread()))
// {
// System.err.println("Threadpool: Killing blocked thread: "+t);
// t.stop();
// }
// }
}
/**
* Get the string representation.
* @return The string representation.
*/
public synchronized String toString()
{
StringBuffer buf = new StringBuffer();
buf.append(SReflect.getInnerClassName(getClass()));
buf.append("(poolsize=");
buf.append(pool.size());
buf.append(", running=");
buf.append(running);
buf.append(")");
return buf.toString()+" "+hashCode();
}
//-------- helper methods --------
/**
* Create some pool.
* @param num The number of pool.
*/
protected synchronized void addThreads(int num)
{
for(int i=0; i<num; i++)
{
Thread thread = new ServiceThread();
// Thread gets daemon state of parent, i.e. thread daemon state would
// depend on called thread, which is not desired.
thread.setDaemon(false);
pool.add(thread);
thread.start();
// System.out.println("poola: "+pool.size());
}
}
/**
* Get a thread for a task.
*/
protected synchronized Thread getThread(Runnable task)
{
return (Thread)threads.get(task);
}
/**
* The task for a given thread.
*/
protected synchronized Runnable getTask(Thread thread)
{
Runnable ret = null;
if(thread instanceof ServiceThread)
{
ret = ((ServiceThread)thread).getTask();
}
return ret;
}
//-------- inner classes --------
/**
* A service thread executes tasks.
*/
public class ServiceThread extends Thread
{
//-------- attributes --------
/** The actual task. */
protected Runnable task;
/** The start time. */
protected long start;
//-------- constructors --------
/**
* Create a new thread.
*/
public ServiceThread()
{
super(group, "ServiceThread_"+(++threadcnt));
}
//-------- methods --------
/**
* Dequeue an element from the queue
* and execute it.
*/
public void run()
{
boolean terminate = false;
while(running && !terminate)
{
try
{
this.task = ((Runnable)tasks.dequeue(strategy.getThreadTimeout()));
// this.task = ((Runnable)tasks.poll(strategy.getThreadTimeout(), TimeUnit.MILLISECONDS));
threads.put(task, this);
this.start = System.currentTimeMillis();
String oldname = this.getName();
this.setName(task.toString());
try
{
this.task.run();
}
catch(ThreadDeath e){}
catch(Throwable e)
{
e.printStackTrace();
}
this.setName(oldname);
}
catch(IBlockingQueue.ClosedException e)
{
task = null;
terminate = true;
}
catch(IBlockingQueue.TimeoutException e)
{
task = null;
terminate = strategy.threadTimeoutOccurred();
}
// catch(Exception e)
// {
// task = null;
// terminate = true;
// e.printStackTrace();
// }
if(task!=null)
{
threads.remove(task);
this.task = null;
terminate = strategy.taskFinished();
}
}
synchronized(ThreadPool.this)
{
pool.remove(this);
}
}
/**
* Get the runnable (the task).
* @return The runnable.
*/
public Runnable getTask()
{
return this.task;
}
/**
* Get the string representation.
*/
public String toString()
{
return super.toString()+":"+hashCode();
}
}
//-------- static part --------
static int cnt = 0;
static int todo;
/**
* Main for testing.
* @param args The arguments.
*/
public static void main(String[] args)
{
final ThreadPool tp = new ThreadPool(new DefaultThreadPoolStrategy(10, 100, 10000, 4));
int max = 10000;
todo = max;
final long start = System.currentTimeMillis();
for(int i=0; i<max; i++)
{
tp.execute(new Runnable()
{
int n = cnt++;
public void run()
{
String t = Thread.currentThread().toString();
System.out.println("a_"+this+" : "+t);
long cnt = 0;
for(int i=0; i<1000000; i++)
{
cnt++;
}
// try{Thread.sleep(100);}
// catch(InterruptedException e){}
System.out.println("b_"+this+" : "+t);
synchronized(tp)
{
todo--;
if(todo==0)
System.out.println("Execution finished. Needed: "+(System.currentTimeMillis()-start));
}
}
public String toString()
{
return "Task_"+n;
}
});
}
}
}