Tuesday, August 28, 2007

Synchronization Simplified

Most of the Java applications are multi-threaded due to the obvious reasons of better performance and better utilization of resources.

Hence in such applications there are many occasions when two or more threads share an object. Which may lead to situations called “race condition” in which two or more threads are trying access the methods of same object. For Example there may be a case when one thread is writing something to an object while another thread is trying to read from it. In most situations, a race conditions is more subtle and less predictable, because you cannot be sure when the context switch will occur. This can cause the program to run right one time and wrong the next.

When two or more threads need to access an object which is a shared resource they need some way to ensure that the resource will be used by only one thread at a time. The process by which this achieved is called synchronization.

The access to the object can be serialized by the process of synchronization. This is achieved by the use of the keyword “synchronized”. You can synchronize your code in two ways:

Modify the methods of the object with the synchronized keyword. Which makes the object “thread-safe” which implies it is safe to use this object in a multi-threaded application. For Example a Vector is thread-safe whereas an ArrayList is not.

If you want to use an object which is not thread-safe in a multithreaded application we have to use synchronized blocks.

For Example if Person is not thread safe and p is an object of person with Thread t.

Class Person

{

int age;

public void setAge(int age);

}

To use p in a thread safe manner we use

synchronized(p)

{

p.setAge();

}

A Simple Example for understanding Synchronization.

class Person

{

int age;

public void setAge(int age)

{

this.age = age ;

}

public int getAge()

{

return age;

}

}

class MyThread extends Thread

{

Person p;

int age;

public MyThread(Person p, int age)

{

this.p = p;

this.age = age;

}

public void run()

{

p.setAge(age);

}

}

public class TestSynchronization

{

public static void main(String args[]) throws Exception

{

Person p = new Person();

MyThread t1 = new MyThread(p,1);

MyThread t2 = new MyThread(p,2);

MyThread t3 = new MyThread(p,3);

t1.start();

t2.start();

t3.start();

System.out.println(“”+p.getAge());

}

}

The output of this simple program is unpredictable because the three threads t1,t2,t3 go into a race condition and depending on the context switch the execution of threads take place. The output can be 1, 2, 3 when we expect 3.

To make the program behave in a predictable way we use the synchronized keyword.

We just have to make the methods setAge() and getAge() synchronized.

Hence it is advisable that in multi-threaded applications we use thread-safe classes like Vector, HashTable, etc.

If it is inevitable to use some of the collections in multithreaded environment we can use the Collections class to make synchronized ArrayList, HashMap etc.

ArrayList synchronizedArrayList = Collections.synchronizedList(arraylist);

By the way the HttpSession class is also not thread safe !!!.

That’s all about synchronization….. happy multithreading ….be thread-safe ;-)

No comments: