Aug 20, 2010

Java concurrency and deadlock problems

It's known by many programmers that the use of the key word 'synchronized' is either for establishing methods or establishing synchronized code blocks that affect the optimal performance of the applications with regard to process speed. Although misuse of synchronized code blocks is forbidden. Constant improvements of the JVM through the years has made the percentage of performance affected versus the benefits to resolve concurrency problems tilt the balance towards the latter. The main issue associated with the misuse of synchronized code blocks is, if we increase such methods or blocks in an application then the greater the chance that at some point in the program's execution, DeadLock may occur and the application starts an infinite loop and finally is forced to restart.

In particular, DeadLock happens when at least two threads try to lock on an object at the same time. In order to be more clear I will give an example: Thread 'A' gets the 'Lock' of the object 'obj1', while thread 'B' gets the 'Lock' of the object 'obj2'. Then thread 'A' tries to get the 'Lock' of 'obj2' before releasing the 'Lock' of 'obj1'. At the same time, thread 'B' tries to get the 'Lock' of 'obj1' before releasing the 'Lock'of 'obj2' . What we have in here is thread 'A' will wait until the thread 'B' releases the 'Lock'of 'obj2' while thread 'B' is waiting for thread 'A' to release the 'Lock' of 'obj1' . So they will be waiting on each other until the judgement day. Let's see the example:
    public static Object obj1 = new Object();
public static Object obj2 = new Object();
public void metodo1() {
synchronized (obj1) {
synchronized (obj2) {
process1();
}
}
}
public void metodo2{
synchronized (obj2) {
synchronized (obj1) {
process2();
}
}
}
As You can see there are two synchronized code blocks in two methods. First thread 'A' invokes to 'method1' and gets the 'Lock' of the object 'obj1', at the same time thread 'B' gets the 'Lock' of the object 'obj2'. Then thread 'A' tries to get the 'Lock' of the 'obj2', but it turns out that thread 'B' already has 'obj2' so thread A will have to wait until 'obj2' is released. But the problem is that thread 'B' is waiting for the release of the object 'obj1' before releasing 'obj2'. Hence DeadLock and both threads will be in an eternal wait.

Knowing when a 'Deadlock' will happen is very difficult because of the low possibility that two threads will gain access to both methods simultaneously. However, it can happen without warning. It may be just once during a period of time or it may happen many times within the same period. To detect this type of problem by just analyzing the code can be difficult. A mistake as mentioned above can be detected easily and infer that the problem can be solved by chaning the order in which the objects are locked. In other words, they must be locked in the same order in both methods in such a way that the 'Deadlock' is not possible. Let's see an example more complex:
  public class Deadlock {
static class Auto {
private final String model;
private final long miles;
public Auto(String model, long ml) {
this.model = model;
this.miles = ml;
}
public String getModel() {
return this.model;
public synchronized long difMiles(Auto auto) {
System.out.println("Calculate Difference in miles ");
return Math.abs((auto.getMiles() - getMiles()))
}
public synchronized long getMiles() {
System.out.println(" Get miles for " + getModel());
return miles;
}
}
public static void main(String[] args) {
final Auto mazda = new Auto("Mazda", 60000);
final Auto renault = new Auto("Renault", 80000);
new Thread(new Runnable() {
public void run() { System.out.println("Difference in miles "
+ mazda.difMiles(renault)); }
}).start();
new Thread(new Runnable() {
public void run() { System.out.println("Difference in miles "
+ renault.difMiles(mazda)); }
}).start();
}
}
As you can see two instances of Auto class were created. The Auto class have a method which calculate the difference between two cars by miles. When the first thread is executed the Mazda object invokes difMiles method and gains the Lock of the object Mazda. On the other hand, the second thread happens at the same time and this object gains Lock of the 'Renault' object. But what happens when both threads invoke getMiles method using the object that has been passed as a prameter?.

The first thread tries to gain the Lock of 'Renault' object while the second thread tries to gain the Lock on the 'Mazda' object. As you can see, neither thread is going to get what they want and the application will get hung up. It is exactly like the first case we looked at. It is just that this time it is not so obvious and truly things could get worse when there are more lines of code. This case is a seed to germinate a potential 'DeadLock'. If you executed this code 10 consecutive times, it will probably do fine for 6 or 7 of those times, but at least 3 or 4 times it will make the application get hung up.

The fact that the application gets hung up only sometimes, makes it more difficult to find the cause of the problem. You might think there is no reason in real life for two threads to start doing such operations, therefore, let's see a typical example a little more close to real life. Let's suppose that we have to do a transfer of money between two cash accounts. We will have two objects 'account1' and 'account2' which are, in this instance, of the same Account Class. The code would go like this:
  public class Deadlock {
static class Cash {
double balance;
public Cash(double balInit) {
this.balance = balInit;
}
public void debit(double val) {
balance += val;
}
public void credit(double val) {
balance -= val;
}
public double getBalance() {
return balance;
}
}
static class OperCash{
public void transfer(Cash from, Cash to, double val) {
System.out.println("balance transfer...");
System.out.println("lock acquired from...");
synchronized (from) {
System.out.println("lock acquired to...");
synchronized (to) {
if (from.getBalance() >= val) {
from.debit(val);
to.credit(val);
System.out.println("transfer finished...");
}
}
}
}
}
public static void main(String[] args) {
final Cash cash1 = new Cash(60000);
final Cash cash2 = new Cash(80000);
final OperCash opc = new OperCash();
new Thread(new Runnable() {
public void run() {
opc.transfer(cash1, cash2, 20000);
}
}).start();
new Thread(new Runnable() {
public void run() {
opc.transfer(cash2, cash1, 10000);
}
}).start();
}
}
The messages printed in every step are there, not just to show us what is happening during execution, but also to delay a little of the execution of the threads as it would happen in a real application which responds to multiple calls. As expected, this code is intended to get stuck in a 'DeadLock' at some point of its life cycle. This is because different threads can call the same method with parameters ordered in a different way, such as in previous examples.

Well, now the question we've been raiding is how to prevent such problems from happening when we need to synchronize access to an object?. One of the possible solutions is to carefully sort the way in which the synchronizaed methods are called from different threads or the order in which parameters are passed to methods containing synchronized code blocks. In order to do this, we must observe in what order the locks are obtained within the method. This is usually a very hard task when dealing with very complex applications. Fortunately, more recent versions of Java language give us a package which help us deal with these kinds of problems. I am talking about package java.util.concurrent.locks.

For now I am just going to say that this package gives us an interface called 'Lock' which is implemented by the ReentrantLock class. This kind of object works very similar to synchronized code blocks, as we can have just one 'Lock' at the same time. Its main advantage is that it allows us to schedule alternative executions if the 'Lock' object has been obtained by another thread. The way to use this object to solve the problems presented above, I leave for another post.