2.02.2016

Learning Java schronized

1. "synchronized" keyword on member method (lock on object)

The synchronized keyword on member method locks the object instance. If you have multiple threads using this object instance and calling the synchronized method, only one thread at a time can access within the synchronized block.
Note: The member methods without "synchronized" are not affected by the lock.
public class SynchronizeLab {
    public synchronized void doA() {
        System.out.println(String.format("%s is running doA at %d.", Thread.currentThread().getName(), System.currentTimeMillis()));
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void doB() {
        System.out.println(String.format("%s is running doB at %d.", Thread.currentThread().getName(), System.currentTimeMillis()));
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Now we have two threads triggering doA() and doB() at the same time. What will the output look like?
========== Note: The order is not guarantee ===
Thread-0 is running doA at 1454419074237.
Thread-1 is running doB at 1454419079239.
===============================================
As one thread is holding the lock, another thread has to wait until the first thread release the lock. Note: the synchronized method is the same as synchronized statements as below.
    public void doA() {
        synchronized(this) {
            .....
        }
    }
To improve the concurrency with fine-grained synchronization, the synchronized statements can also be used to lock on different object so that the lock on one object won't affect the other.

2. "synchronized" keyword on static method (lock on class)

The synchronized keyword on static method locks the class.
Note: The member methods with "synchronized" are not affected by the lock as they are object level lock.
public class SynchronizeLab {
    public synchronized static void doC() {
        System.out.println(String.format("%s is running doC at %d.", Thread.currentThread().getName(), System.currentTimeMillis()));
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Quiz: Assuming we have five threads triggering doA(), doB(), doC(), doD() and doE() at the same time, what will the output look like?

public class SynchronizeLab {
    private Object lockD = new Object();
    private Object lockE = new Object();

    /**
     * Thread holds the lock of the object
     */
    public synchronized void doA() {
        System.out.println(String.format("%s is running doA at %d.", Thread.currentThread().getName(), System.currentTimeMillis()));
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * Thread holds the lock of the object
     */
    public synchronized void doB() {
        System.out.println(String.format("%s is running doB at %d.", Thread.currentThread().getName(), System.currentTimeMillis()));
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * Thread holds the lock of the class
     */
    public synchronized static void doC() {
        System.out.println(String.format("%s is running doC at %d.", Thread.currentThread().getName(), System.currentTimeMillis()));
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * Thread holds the lock of the member variable
     */
    public void doD() {
        synchronized (lockD) {
            System.out.println(String.format("%s is running doD at %d.", Thread.currentThread().getName(), System.currentTimeMillis()));
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Thread holds the lock of the member variable
     */
    public void doE() {
        synchronized (lockE) {
            System.out.println(String.format("%s is running doE at %d.", Thread.currentThread().getName(), System.currentTimeMillis()));
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

========== Note: The order is not guarantee ===
Thread-2 is running doC at 1454595907992.
Thread-1 is running doB at 1454595907992.
Thread-3 is running doD at 1454595907993.
Thread-4 is running doE at 1454595907993.
Thread-0 is running doA at 1454595912995.
===============================================
Only doA and doB have exclusive lock on the same object.