ReentrantLock and synchronized of java concurrent programming

Before jdk5, only synchronized and lock were used to coordinate access to shared objects. JDK added a new locking mechanism: ReentrantLock. lock is not a replacement for the built-in lock, but a complement. This article mainly compares the similarities, differences and applicable scenarios of the two step by step. If there is any misunderstanding, I hope you can point it out.

How is synchronized achieved?

Synchronized is one of the most common and simplest methods to solve concurrency problems in Java, which effectively meets the three requirements of thread safety: atomicity, visibility and orderliness.

synchronized can be used in three places:

  • Modifies ordinary methods. The lock is the instance object .
  • Decorate static methods. The lock is the class .
  • Modified code blocks. The object inside the brackets is locked .

Synchronized relies on a monitor (monitor lock) in the object header. When executing a synchronized modified method or code block, it will first try to obtain the monitor. If the monitor is successfully obtained, it can be executed. Otherwise, you have to wait until the monitor can be obtained. The reentrancy of synchronized is also easy to explain. If a thread has already acquired the monitor, acquiring it again will increase the counter by one, instead of waiting for the lock. The counter is decremented by 1 when it exits, and when it reaches 0, other waiting threads can be woken up . Of course, these implementations of the JVM have been taken care of for us, so we will feel that synchronized is very simple to use.

Why use ReentrantLock?

Synchronized was introduced earlier, which is convenient and simple to use. The so-called success is also Xiao He is also Xiao He, too simple, there will be some problems:

  • A thread that is already waiting to acquire a lock cannot be interrupted. If a thread has been unable to acquire the lock, it will wait forever. ReentrantLock can use interrupts and timed locks, wait for a certain time and return if it is not acquired.
  • The locking rules cannot be changed, and the locking rules of the non-blocking structure cannot be implemented.
  • synchronized If you encounter a deadlock problem, the solution to recovery is to restart the program.
  • In many scenarios, read and read do not need to be mutually exclusive, and synchronized rudely makes all operations mutually exclusive. ReadWriteLock can implement a read-write lock, using two Lock objects, one for reading and one for writing.
  • Synchronized is an unfair lock and cannot adapt to scenarios that require fair locks. ReentrantLock is divided into fair lock and unfair lock.

The so-called fair lock is to wake up the threads in the waiting queue according to the FCFS principle every time it wakes up. When an unfair lock is awakened, other waiting threads go to grab the lock together, and the later thread may get the lock first than the first thread, and can jump in the queue, which is a manifestation of unfairness .

In the case of fierce competition, the performance of unfair locks is higher than that of fairness , because queue cutting can improve throughput. For example, thread A holds the lock and thread B is waiting for the lock. At this point, thread A is releasing the lock, and B will wake up and try to acquire the lock. At this time, thread C is likely to acquire the lock before C is fully awakened, and the lock is acquired earlier, which of course improves the throughput.

The corresponding ReentrantLock features are:

  • It can be interrupted and timed, which alleviates the problem of deadlock.
  • Fair lock, which can realize the thread first come first to acquire the lock
  • There can be ReadWriteLock to implement read-write lock, and read and read do not have to be mutually exclusive.

To sum up, synchronized is not flexible enough, which is why ReentrantLock appears. A good example is the lock segmentation technology. For example ConcurrentHashMap, it divides the segment to segment the lock and improves the performance in the concurrent environment, and the ReenterantLock is used in the source code.

/**
 * Stripped-down version of helper class used in previous version,
 * declared for the sake of serialization compatibility
 */
static class Segment<K,V> extends ReentrantLock implements Serializable {
    private static final long serialVersionUID = 2249069246763182397L;
    final float loadFactor;
    Segment(float lf) { this.loadFactor = lf; }
}

When to use ReentrantLock and when to use synchronized?

The price of the flexibility of use that ReentrantLock brings is that you need to be responsible for the lock operation carefully, such as unlock, the lock will be released, and it is naturally not as worry-free as synchronized.

Synchronized has some upgrades in java6, so the performance of the two is actually not much different. So I think that if you need more flexibility for lock operations or waiting queues or if you need locks to be fair, use ReentrantLock. Otherwise, using synchronized is enough.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325671607&siteId=291194637