Java Synchronization: The Lock

Where is the lock?

Consider the following use case: I have class A which have a static variable i. I have method m1() which increase value of i by one everything it is called. 
In a single thread system, it is simple. In multiple-thread system, value of i does not get set properly sometimes. Try to get the following code run by 2 threads a few times, we get inconsistent last value of i and some of them does not even get the last value to be 200.  

public class A {
static int i;
public void m1() {
for (int j = 0; j < 100; j++) {
i++;
System.out.println(i);
}
}
}

Why? Because i++ is not an atomic instruction. If we translate it to byte code, it will be something like:
1 - Read var = i
2 - Increase var by 1
3 - i = var

Let say current value of i = 6. Thread 1 is trying to make it to 7. The first step done var = 7. Increase var by 1 so var = 8. Before thread 1 got chance to write back, thread 2 comes in and read i = 7. Thread 2 increases it by 1 to make i = 8 then write back. Oh it is not right.

Maybe the method m1 should be synchronized. Let's make the code as below:

public class A {
static int i;
public synchronized void m1() {
i++;
System.out.println(i);
}
}

It still doesn't work. Why? Do you notice that whenever you called a synchronized block, you have to pass in a lock object? What does it mean to make a method synchronized? Which lock does it use? Answer is, all Java object has header of 12 bytes. This header has extra information about the object, including the lock. So if you put synchronized at a method, the method use the object lock for synchronization. 
We have 2 threads, 1 object created by each thread. So 2 objects, 2 locks. Each thread has a lock for themselves which doesn't help at all in synchronization.


Multi-thread working on static variable

Problem discussed above. Now what to do? There are 3 options.

1) Create a private final object and use it as a lock

public class A {
static int i;
        static final Object lock;

public void m1()
{
synchronized(lock)
{
i++;
                        System.out.println(i);
}
}
}

2) Synchronize on this.getClass()

Each class has their own natural lock (We don't have to create lock object). We can use them wherever possible.

public class A {
static int i;

public void m1()
{
synchronized(this.getClass())
{
i++;
                        System.out.println(i);
}
}
}

3) Static synchronized. (could you please give example?)
We should avoid this method because we should not make something static just for locking purpose. It will also mess up desired polymophism.



An Extra Question

Consider class A below. There are 4 threads calling 4 methods at the same time. Will any thread need to wait for the lock? NO. Because m1() uses class lock. m2() use object lock. m3() and m4() don't need any lock to run.  (Please validate)

public class A {
synchronized static void m1() {}
synchronized void m2() {}
static void m3() {}
void m4() {}
}

Comments

Popular posts from this blog

JVM Garbage Collection (GC)