22 How to Choose Between Synchronized and Lock Advantages and Disadvantages

22 How to Choose Between synchronized and Lock Advantages and Disadvantages #

In this lesson, we will mainly learn about the similarities and differences between synchronized and Lock, as well as how to choose between them.

Similarities #

There are many similarities between synchronized and Lock, and here we will focus on three major similarities.

  • Both synchronized and Lock are used to protect resources and ensure thread safety.

This is their basic function and there is no doubt about it.

  • Both can guarantee visibility.

For synchronized, if thread A performs operations before entering the synchronized block or within the synchronized block, it is visible to thread B that acquires the same monitor lock afterwards. In other words, thread B can see the operations performed by thread A before. This also reflects a principle of happens-before in synchronized.

img

For Lock, it is the same as synchronized, they both can guarantee visibility. As shown in the figure, all operations before unlocking are visible to all operations after locking.

img

If you don’t understand what visibility means, it may be difficult to understand at this time. You can review this lesson after learning about the Java memory model in this course, and then you will have a clear understanding.

  • Both synchronized and ReentrantLock have the feature of reentrancy.

ReentrantLock is the main implementation class of the Lock interface. When comparing synchronized and Lock, we will also compare them using the main implementation class of Lock. Reentrancy means that if a thread has already acquired a lock and now tries to request the same lock that it has already acquired, it can continue to use the lock it holds without releasing it. This is reentrancy. If the lock must be released before applying for it again, it is not reentrant. Both synchronized and ReentrantLock have the feature of reentrancy.

Differences #

Now let’s take a look at the differences between synchronized and Lock. Just like the similarities, there are also many differences between them. Here, we will explain the 7 major differences.

  • Usage difference

The synchronized keyword can be added to a method without specifying a lock object (the lock object in this case is this). It can also create a synchronized block and customize the monitor lock object. On the other hand, the Lock interface must explicitly use the lock() method to lock and the unlock() method to unlock. Generally, the unlock() method will be used in the finally block to ensure unlocking, to prevent deadlocks.

Different from the explicit locking and unlocking of Lock, the locking and unlocking of synchronized are implicit, especially when exceptions are thrown, it can ensure that the lock is released. However, there is no such expression in Java code.

  • Difference in the order of locking and unlocking

For Lock, if there are multiple locks, Lock does not have to unlock them in the reverse order of locking. For example, we can acquire Lock1 first, then acquire Lock2, and unlock Lock1 first and then unlock Lock2, the locking and unlocking have a certain degree of flexibility, as shown in the code.

lock1.lock();

lock2.lock();

...

lock1.unlock();

lock2.unlock();

However, synchronized cannot achieve this. The unlock order of synchronized must be exactly the reverse of the lock order. For example,

synchronized(obj1){

    synchronized(obj2){

        ...

    }

}

Here, the order is to lock obj1 first, then lock obj2, then unlock obj2 first, and finally unlock obj1. This is because the locking and unlocking of synchronized is implemented by the JVM. After executing the synchronized block, it will automatically unlock. Therefore, the locking and unlocking have to follow the nesting order of synchronized, and cannot be controlled manually.

  • Inflexibility of synchronized lock

Once a thread acquires a synchronized lock, if other threads still want to acquire it, they can only be blocked until the thread holding the lock finishes running or releases the lock due to an exception. If the thread holding the lock holds it for a long time before releasing it, the overall efficiency of the program will be reduced. Moreover, if the thread holding the lock never releases it, the thread trying to acquire the lock can only wait forever.

On the other hand, in the process of waiting for the lock with Lock, if the lockInterruptibly method is used, if it takes too long and you don’t want to continue waiting, you can interrupt and exit. You can also try to acquire the lock using the tryLock() method. If the lock cannot be acquired, you can do other things, which is more flexible.

  • Synchronized lock can only be owned by one thread at a time, but Lock lock does not have this limitation

For example, in a read-write lock, the read lock can be held by multiple threads at the same time, but synchronized cannot achieve this.

  • Difference in principle

Synchronized is an intrinsic lock, and the principle of obtaining and releasing locks is implemented by the JVM. It can be divided into biased lock, lightweight lock, and heavyweight lock.

Lock has different principles depending on the implementation. For example, ReentrantLock internally uses AQS to obtain and release locks.

  • Can fair/unfair be set

A fair lock means that when multiple threads are waiting for the same lock, they are granted the lock in the order they wait. ReentrantLock and other Lock implementation classes can be set as fair or unfair according to their needs, while synchronized cannot be set.

  • Performance difference

In Java 5 and earlier, synchronized had lower performance. However, this changed after Java 6 because JDK has optimized synchronized in many ways, such as adaptive spin locking, lock elision, lock coarsening, lightweight lock, and biased lock. Therefore, the performance of synchronized in later versions of Java is not worse than Lock.

How to choose #

After discussing the similarities and differences between synchronized and Lock, let’s look at how to choose between them. Both Java Concurrency in Practice and Core Java agree on the following:

  1. If possible, it is best not to use both Lock and synchronized. Because in many cases, you can use the mechanisms in the java.util.concurrent package, which will handle all the locking and unlocking operations for you. Therefore, it is recommended to use utility classes to lock and unlock.
  2. If the synchronized keyword is suitable for your program, please try to use it. This can reduce the amount of code and the probability of mistakes. Because if you forget to unlock in finally, it may cause serious problems in the code, while using synchronized is safer.
  3. Only use Lock if you need its special features, such as try lock, interruptibility, and timeout functions.