Creating your own thread dispatcher in Java

Java offers ExecutorService, which can be used for managing and dispatching threads. But ExecutorService has limitations. One of them being the fact that if you create a fixed thread pool, you need to define all your threads up front. What if you’ll be spawning a million threads (but only a handful will be running at a given moment)? That would take up a lot of memory. And in some cases, you may need to know the outcome of certain threads to schedule new threads. It’s hard and cumbersome to do this using ExecutorService.

On the other hand, you can easily create your own thread dispatcher service, which can be limited to run only a certain number of threads at a time. See code snippet below:

final static int MAX_THREADS_AT_A_TIME = 10;
static int currentlyRunningThreadsCount = 0;
static Object dispatcherLock = new Object();

public static void main(String args[])
{
	for(int i=0; i<100; i++)
	{
		synchronized(dispatcherLock)
		{
			currentlyRunningThreadsCount++;
		}
		final int thisThreadCount = i+1;
		new Thread(new Runnable() {
			@Override
			public void run() {
				//Do something
				System.out.println("Thread "+thisThreadCount+" starting.");
				try { Thread.sleep(5000); } catch(InterruptedException e) { }
				System.out.println("Thread "+thisThreadCount+" finished.");
				synchronized(dispatcherLock)
				{
					currentlyRunningThreadsCount--;
					dispatcherLock.notify();
				}
			}
		}).start();
		if(currentlyRunningThreadsCount >= MAX_THREADS_AT_A_TIME)
		{
			synchronized(dispatcherLock)
			{
				try { dispatcherLock.wait(); } catch(InterruptedException e) { }
			}
		}
	}
}

Let’s break it down. In this case we’re spawning 100 threads, but limiting it to run only 10 threads at a time. Everything outside of the thread runnable is part of the “dispatcher” service. The dispatcher loop uses a counter currentlyRunningThreadsCount to track how many threads are running at a time. If there are 10, it wait()’s on a lock object. And as each thread finishes its work, it decrements currentlyRunningThreadsCount and calls notify() on the lock object, which wakes up the dispatcher and it moves on to spawn more.

Pretty simple, right?!