/*
     ThreadPoolJob.java
*/

package com.cg;

public interface ThreadPoolJob
{
     
public void init(ThreadContext tc);
     
public void doJob();
     
public void dispose();
}

//----------------------------------------------//

/*
     ThreadPool.java
*/

package com.cg;

import java.util.ArrayList;
import java.util.List;
 
public class ThreadPool
{
     List<ThreadPoolJob> pool;
     
private int noOfThread;
     Thread[] threads;
     
private boolean canRun = true;
     
     
public ThreadPool(int noOfThread)
     {
          
this.noOfThread = noOfThread;
          pool = 
new ArrayList<ThreadPoolJob>();
          threads = 
new Thread[noOfThread];
          
for(int i=0;i<noOfThread;++i)
          {
               threads[i] = 
new Thread(new ThreadPoolRunnable());
               threads[i].start();
          }
     }
     
     
public void interruptAllThreads()
     {
          
for(Thread thread : threads)
          {
               thread.interrupt();
          }
     }
     
     
public void addJob(ThreadPoolJob poolJob,ThreadContext ctx)
     {
          poolJob.init(ctx);
          
synchronized(pool)
          {
               pool.add(poolJob);
               pool.notifyAll();
          }
     }
     
     
     
class ThreadPoolRunnable implements Runnable
     {
          ThreadPoolJob job;
          
public void run()
          {
               l1: 
while(true)
               {
                    
synchronized(pool)
                    {
                         
try
                         {
                              while
(canRun && pool.size()==0)
                              {
                                   
if(!canRun)
                                   {
                                        
break l1;
                                   }
                                   pool.wait();
                              }
                              
if(pool.size()>0)
                                   job = pool.remove(0);
                              
else if(!canRun)
                                   
break;
                         }
                         
catch(InterruptedException e)
                         {
                              e.printStackTrace();
                         }
                    }
                    job.doJob();
                    job.dispose();
               }
               System.out.println(
"exiting ..");
          }
     }
     
     
public void exitAfterAllJobs()
     {
          
synchronized(pool)
          {
               canRun = false;
               pool.notifyAll();
          }
     }
}

//-----------------------------------------------------//

/*
     ThreadContext.java
*/

package com.cg;

import java.util.HashMap;
import java.util.Map;
 
public class ThreadContext 
{
     
private Map<String,Object> arguments;
     
     
public ThreadContext()
     {
          arguments = 
new HashMap<String,Object>();
     }
     
     
public Map<String,Object> getThreadContext()
     {
          
return arguments;
     }
     
     
public Object getThreadContextValue(String val)
     {
          
return arguments != null ? arguments.get(val) : null;
     }
     
     
public void setThreadContextValue(String key,Object val)
     {
          
if(arguments!=null)
               arguments.put(key,val);
     }
     
     
}

//------------------------------------------

/*
     Test.java
*/

package com.cg;

class Test
{
     
public static void main(String arg[]) throws Exception
     {
          ThreadPool n = 
new ThreadPool(2);
          
for(int i=0;i<5;++i)
          {
               ThreadContext tc = 
new ThreadContext();
               tc.setThreadContextValue(
"name","Job_" + i);
               tc.setThreadContextValue(
"maxVal",i*3+1);
               n.addJob(
new CountDownJob(),tc);
          }
          
//Thread.sleep(300);
          
n.exitAfterAllJobs();
     }
}
 
class CountDownJob implements ThreadPoolJob
{
     
private ThreadContext tc;
     Integer maxVal;
     
     
public void init(ThreadContext tc) 
     {
          
this.tc = tc;
     }
 
     
public void doJob() 
     {
          String name = (String) tc.getThreadContextValue(
"name");
          
int maxVal = (Integer) tc.getThreadContextValue("maxVal");
          
for(int i=0;i<maxVal;++i)
          {
               
try
               {
                    
System.out.println("Job : " + name + ", value = " + i);
                    Thread.sleep(500);
               }
               
catch(Exception e)
               {
                    e.printStackTrace();
               }
          }
     }
 
     
public void dispose() 
     {
          System.out.println(tc.getThreadContextValue(
"name") + " diposed !");
     }
     
}

//---------------------------------------------

Output:

Job : Job_0, value = 0
Job : Job_1, value = 0
Job_0 diposed !
Job : Job_2, value = 0
Job : Job_1, value = 1
Job : Job_2, value = 1
Job : Job_1, value = 2
Job : Job_2, value = 2
Job : Job_1, value = 3
Job : Job_2, value = 3
Job_1 diposed !
Job : Job_3, value = 0
Job : Job_2, value = 4
Job : Job_3, value = 1
Job : Job_2, value = 5
Job : Job_3, value = 2
Job : Job_2, value = 6
Job : Job_3, value = 3
Job_2 diposed !
Job : Job_4, value = 0
Job : Job_3, value = 4
Job : Job_4, value = 1
Job : Job_3, value = 5
Job : Job_4, value = 2
Job : Job_3, value = 6
Job : Job_4, value = 3
Job : Job_3, value = 7
Job : Job_4, value = 4
Job : Job_3, value = 8
Job : Job_4, value = 5
Job : Job_3, value = 9
Job : Job_4, value = 6
Job_3 diposed !
exiting ..
Job : Job_4, value = 7
Job : Job_4, value = 8
Job : Job_4, value = 9
Job : Job_4, value = 10
Job : Job_4, value = 11
Job : Job_4, value = 12
Job_4 diposed !
exiting ..