Java Concurrency – Part 3 : Synchronization with intrinsic locks

This entry is part 3 of 7 in the series Java Concurrency Tutorial

After learning how to create threads and manipulate them, it’s time to go to most important things : synchronization.

Synchronization is a way to make some code thread safe. A code that can be accessed by multiple threads must be made thread safe. Thread Safe describe some code that can be called from multiple threads without corrupting the state of the object or simply doing the thing the code must do in right order.

For example, we can take this little class :

public class Example {
    private int value = 0;    

    public int getNextValue(){
        return value++;
    }
}

It’s really simple and works well with one thread, but absolutely not with multiple threads. An increment like this is not a simple action, but three actions :

  • Read the current value of “value”
  • Add one to the current value
  • Write that new value to “value”

Normally, if you have two threads invoking the getNextValue(), you can think that the first will get 1 and the next will get 2, but it is possible that the two threads get the value 1. Imagine this situation :

Thread 1 : read the value, get 0, add 1, so value = 1
Thread 2 : read the value, get 0, add 1, so value = 1
Thread 1 : write 1 to the field value and return 1
Thread 2 : write 1 to the field value and return 1

These situations come from what we call interleaving. Interleaving describe the possible situations of several threads executing some statements. Only for three operations and two threads, there is a lot of possible interleavings.

So we must made the operations atomic to works with multiple threads. In Java, the first way to make that is to use a lock. All Java objects contains an intrinsic locks, we’ll use that lock to make methods or statement atomic. When a thread has a lock, no other thread can acquire it and must wait for the first thread to release the lock. To acquire the lock, you have to use the synchronized keyword to automatically acquire and release a lock for a code. You can add the synchronized keyword to a method to acquire the lock before invoking the method and release it after the method execution. You can refactor the getNextValue() method using the synchronized keyword :

public class Example {
    private int value = 0;    

    public synchronized int getNextValue(){
        return value++;
    }
}

With that, you have the guarantee that only thread can execute the method at the same time. The used lock is the intrinsic lock of the instance. If the method is static, the used lock is the Class object of Example. If you have two methods with the synchronized keyword, only one method of the two will be executed at the same time because the same lock is used for the two methods. You can also write it using a synchronized block :

public class Example {
    private int value = 0;

    public int getNextValue() {
        synchronized (this) {
            return value++;
        }
    }
}

This is exactly the same as using the synchronized keyword on the method signature. Using synchronized blocks, you can choose the lock to block on. By example, if you don’t want to use the intrinsic lock of the current object but an other object, you can use an other object just as a lock :

public class Example {
    private int value = 0;

    private final Object lock = new Object();

    public int getNextValue() {
        synchronized (lock) {
            return value++;
        }
    }
}

The result is the same but has one difference, the lock is internal to the object so no other code can use the lock. With complex classes, it not rare to use several locks to provide thread safety on the class.

There is an other issue with multiple threads : the visibility of the variables. This seems when a change made by a thread is visible by an other thread. For performance improvements, the Java compiler and virtual machines can made some improvements using registers and cache. By default, you have no guarantee that a change made by a thread is visible to an other thread. To make a change visible to an other thread, you must use synchronized blocks to ensure visibility of the change. You must use synchronized blocks for the read and for the write of the shared values. You must make that for every read/write of a value shared between multiple threads.

You can also use the volatile keyword on the field to ensure the visibility of read/write between multiple threads. The volatile keyword ensure only visibility, not atomicity. The synchronized blocks ensure visibility and atomicity. So you can use the volatile keyword on fields that doesn’t need atomicity (if you make only read and write to the field without depending on the current value of the field by example).

You can also note that this simple example can be solved using AtomicInteger, but that will be covered later in an other part of the posts.

Pay attention that trying to solve thread safety on a problem can add new issues of deadlock. By example, if thread A owns the lock 1 and are waiting for the lock 2 and if lock 2 is acquired by thread B who waits on lock 1, there is a deadlock. Your program is dead. So you have to pay great attention to the locks.

There is several rules that we must keep in mind when using locks :

  1. Every mutable fields shared between multiple threads must be guarded with a lock or made volatile, if you only need visibility
  2. Synchronize only the operations that must synchronized, this improve the performances. But don’t synchronize too few operations. Try to keep the lock only for short operations.
  3. Always know which locks are acquired and when there are acquired and by which thread
  4. An immutable object is always thread safe

Here we are, I hope that this post helps you to understand thread safety and how to achieve it using intrinsic locks. In the next posts, we’ll see another synchronization methods.

Series Navigation<< Java Concurrency – Part 1 : Threads<< Java Concurrency – Part 4 : SemaphoresJava Concurrency – Part 5 : Monitors (Locks and Conditions) >>
 

  • chris

    Very nice post!
    Short, clear, complete.

    Think about embracing the comment from DZone: Add a notice about AtomicInteger as substitute for your increment example (your example is still good to explain the point).

    • Baptiste Wicht

      Thanks !

      I will add the notice, but there will be another post about the Atomic Variables later.

  • chris

    Very nice post!
    Short, clear, complete.

    Think about embracing the comment from DZone: Add a notice about AtomicInteger as substitute for your increment example (your example is still good to explain the point).

    • Baptiste Wicht

      Thanks !

      I will add the notice, but there will be another post about the Atomic Variables later.

  • DerUU

    I don’t understand the difference between using another object instead “this” as parameter. Could you please provide an example? It says “the lock is internal to the object so no other code can use the lock” but I can’t figure out what does it exactly means, for me es exactly the same to use “this”.

    Thanks for the articles, are very useful.

    • Baptiste Wicht

      Hi,

      Imagine, you have a class named ProtectedObject where all the methods are synchronized. This object is shared between threads. Now imagine that the thread A makes that :

      ProtectedObject object = getProtectedObject();

      synchronized (object){
      //Operation 10 minutes
      }

      During 10 minutes, the ProtectedObject cannot be used by all the other threads and that destroy the synchronization policy of ProtectedObject. So if you use an other lock instead of the implicit this (a private final lock generally), this case cannot arrive, the lock cannot escape.

      The other advantage is that you can have several locks to synchronize the same class.

      I hope this explanation is better.

      • DerUU

        Mmmm… I am not sure If I got it, let me write some suppositions to know If I am right, correct me please:

        a) One class with one method which is synchronized and uses itself as monitor (“this” as parameter) is equivalent to that class with the same method but using any another object as monitor. Only one thread can use that method, but yes the rest of non synchronized methods.

        b) One class with two methods synchronized both by the same monitor object (this or whatever) can be only used by one thread, calling just one of the methods, not both at same time.

        c) One class with two methods synchronized, one of them by (this or whatever) monitor object and the second one by another different monitor object can used by two threads at same time, one thread calling method numb 1 and the second thread calling methods numb 2, but not the two threads calling the same method.

        d) The object used as monitor is indifferent, I can use whatever, and could not to have any relation with the methods or class, for example I can use a object monitor which is located at any other class where no synchronized is being used. In your example above if I could this with the same result, right?:

        ProtectedObject object = getProtectedObject();

        synchronized (anotherObject){
        //Operation 10 minutes
        }

        Sorry for long post and for not my perfect my english, thanks in advance.

        • Baptiste Wicht

          Yes, I think you got it ;)

          Your suppositions are right.

          For d), yes you can use any Java objects (not primitives) but you must have access to it, you cannot use a private in other class, but this is logical. But normally, we don’t share locks like that except in some specific cases.

  • DerUU

    I don’t understand the difference between using another object instead “this” as parameter. Could you please provide an example? It says “the lock is internal to the object so no other code can use the lock” but I can’t figure out what does it exactly means, for me es exactly the same to use “this”.

    Thanks for the articles, are very useful.

    • Baptiste Wicht

      Hi,

      Imagine, you have a class named ProtectedObject where all the methods are synchronized. This object is shared between threads. Now imagine that the thread A makes that :

      ProtectedObject object = getProtectedObject();

      synchronized (object){
      //Operation 10 minutes
      }

      During 10 minutes, the ProtectedObject cannot be used by all the other threads and that destroy the synchronization policy of ProtectedObject. So if you use an other lock instead of the implicit this (a private final lock generally), this case cannot arrive, the lock cannot escape.

      The other advantage is that you can have several locks to synchronize the same class.

      I hope this explanation is better.

      • DerUU

        Mmmm… I am not sure If I got it, let me write some suppositions to know If I am right, correct me please:

        a) One class with one method which is synchronized and uses itself as monitor (“this” as parameter) is equivalent to that class with the same method but using any another object as monitor. Only one thread can use that method, but yes the rest of non synchronized methods.

        b) One class with two methods synchronized both by the same monitor object (this or whatever) can be only used by one thread, calling just one of the methods, not both at same time.

        c) One class with two methods synchronized, one of them by (this or whatever) monitor object and the second one by another different monitor object can used by two threads at same time, one thread calling method numb 1 and the second thread calling methods numb 2, but not the two threads calling the same method.

        d) The object used as monitor is indifferent, I can use whatever, and could not to have any relation with the methods or class, for example I can use a object monitor which is located at any other class where no synchronized is being used. In your example above if I could this with the same result, right?:

        ProtectedObject object = getProtectedObject();

        synchronized (anotherObject){
        //Operation 10 minutes
        }

        Sorry for long post and for not my perfect my english, thanks in advance.

        • Baptiste Wicht

          Yes, I think you got it ;)

          Your suppositions are right.

          For d), yes you can use any Java objects (not primitives) but you must have access to it, you cannot use a private in other class, but this is logical. But normally, we don’t share locks like that except in some specific cases.

  • DerUU

    Another question, I found this piece of code in an example, does it make sense???
    For me is not necessary the “synchronized (mSurfaceHolder)” becasue the synchronized method prevent to being called for anybody, is it?

    public synchronized void restoreState(Bundle savedState) {

    synchronized (mSurfaceHolder) {
    //Method code
    }
    }

    • Baptiste Wicht

      Yes, it can make sense depending on the context. It indicates that you need two locks for the code of the method.

      Imagine this situation in a class :

      public synchronized void restoreState(Bundle savedState) {
      synchronized (mSurfaceHolder) {
      //Method code
      }
      }

      public void saveState(Bundle state){
      //Some code
      synchronized (mSurfaceHolder) {
      //Critical section
      }
      //Some other code
      }

      The first method need mutual exclusion but not the second one, so the second method is not synchronized. But the two methods use code that need mutual exclusion on an other level (using the mSurfaceHolder lock), so you use a second lock for that code.

      But you must pay attention that this situation can makes deadlocks depending on the order you acquire locks.

      I don’t know if I’m clear.

      • DerUU

        You are very clear, now all fits in my mind, thank you very much man!
        Keep the good work.

  • DerUU

    Another question, I found this piece of code in an example, does it make sense???
    For me is not necessary the “synchronized (mSurfaceHolder)” becasue the synchronized method prevent to being called for anybody, is it?

    public synchronized void restoreState(Bundle savedState) {

    synchronized (mSurfaceHolder) {
    //Method code
    }
    }

    • Baptiste Wicht

      Yes, it can make sense depending on the context. It indicates that you need two locks for the code of the method.

      Imagine this situation in a class :

      public synchronized void restoreState(Bundle savedState) {
      synchronized (mSurfaceHolder) {
      //Method code
      }
      }

      public void saveState(Bundle state){
      //Some code
      synchronized (mSurfaceHolder) {
      //Critical section
      }
      //Some other code
      }

      The first method need mutual exclusion but not the second one, so the second method is not synchronized. But the two methods use code that need mutual exclusion on an other level (using the mSurfaceHolder lock), so you use a second lock for that code.

      But you must pay attention that this situation can makes deadlocks depending on the order you acquire locks.

      I don’t know if I’m clear.

      • DerUU

        You are very clear, now all fits in my mind, thank you very much man!
        Keep the good work.