Sunday, January 17, 2010

Concurrency in Java

Java 5.x introduced the concurrency framework. It make the life of developer easier to run multiple threads. This framework also take care of thread caching this reducing the number of spawned threads in the system.

When the concepts of thread was introduced in the operating systems, it was considered light-weight processes. As the clock speed of the CPU is increasing dramatically and also number of CPU cores available for the programs are increasing, even this light-weight processes are deemed to costly to start. Thus introduced the concept of cached threads. Erlang solve this problem by introducing ultra-light-weight processes. Millions of such processes can be spawned within few seconds. This is not the case in kernel threads. Even when kernel threads are used, there is a cost of context switching to schedule those threads from wait state to run state.

I am new to Java concurrency framework. So I am taking baby steps to learn to use the classes available in Java 5.x. All the concurrency related classes are in java.util.concurrent package.

First step in start using these classes is to introduce Executors class. This class has several class methods to create thread pools.


import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;

ExecutorService threadPool = Executors.newCachedThreadPool();


The above code create a cached thread pool. Behavior of this thread pool is documented here.

Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. Calls to execute will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache. Thus, a pool that remains idle for long enough will not consume any resources. Note that pools with similar properties but different details (for example, timeout parameters) may be created using ThreadPoolExecutor constructors


A task can be submitted to the newly created thread pool for execution. A task must be an instance of Runnable interface. Submitting a task to the ExecutorService will return an instance of Future interface. This is a wrapper around the task submitted. This instance can be used to query the submitted task for completion, as well as to cancel the task.



Future task = threadPool.submit( new Runnable() {
public void run() {
System.out.println( "Hello world from within the thread pool" );
}
});


Finally wait for the task to be completed


while ( !task.isDone() ) {
}


Once the task is completed and thread pool is no-longer necessary, send shutdown message to the thread pool to terminate all the threads created.


threadPool.shutdown();
while (!thread.isTerminated()) {
}


There it is. First Hello world code using the Concurrent Thread Pool in Java. As and when I learn new methods in this framework, I will write about that here.



Until then, happy thread pooling and utilizing all the cores on the system.

Update: Download the source from here

2 comments:

Zoltán Lajos Kis said...

Compare the Java ExecutorService (with fix threads) to Erlang schedulers (with SRQ), and the Runnables/Futures to Erlang processes...
The only difference you will notice is that the thread pool is not preemptive... this might be a disadvantage, or not.
But you can also instantiate millions of Runnables in a few seconds, can't you?

Dude Mangalore said...

Java does not handle the scheduling of threads within ExecutorService. ExecutorService provide a service to run the submitted Runnable/Callable instances within the thread pool. Thread scheduling is done by the underlying operating system. So the real thing to do is to compare the Erlang process scheduler to the underlying thread scheduling. Having said that, Erlang process schedulers is also similar to ExecutorService in Java. Creating process is similar to creating Runnable/Callable instances.

Only difference I see is that, Erlang is efficient in binding the threads to the core so that there is not many context switching and cache busting. Since Java ExecutorService depends on the OS thread scheduling and threads are not bound to the cores, they are not as efficient as Erlang schedulers.

You are right that Erlang schedulers are pre-emptive, in a sense that each Erlang process runs 1000 reductions per cycle and get pre-empted.

My intention of this blog entry is not to say that Erlang is better than Java or vice versa, as I have not done extensive testing on it. The point of this blog is to get the newbies of Java a handle on the concurrency framework.

Thanx for the comments though.. Keep it up...

Book Promotion