In-depth understanding of various locks in Java (below)

Pessimistic locks, optimistic locks, spin locks, biased locks, lightweight locks, heavyweight locks in the first part: in-depth understanding of various locks in Java (part 1)

Let’s talk about other locks today:
In-depth understanding of various locks in Java (below)

4. Fair lock VS unfair lock

The fairness of locks is relative to the order in which locks are acquired.

Fair lock: The order in which the fair lock acquires the lock conforms to the absolute time sequence of the request. The threads that have not acquired the lock will be arranged in a blocking queue, that is, FIFO. The disadvantage is that the throughput is very low, because in addition to the first in the waiting queue One thread, all other threads will be blocked, and CPU waking up the blocked thread also requires a lot of overhead.

Unfair lock: An unfair lock is when multiple threads try to acquire the lock directly, and they will wait until the end of the waiting queue if they fail to acquire it. But if the lock is just available at this time, then this thread can directly acquire the lock without blocking, so an unfair lock may occur after the thread applying for the lock first acquires the lock. The advantage of unfair locks is that they can reduce the overhead of invoking threads, and the overall throughput efficiency is high, because threads have a chance to directly obtain locks without blocking, and the CPU does not have to wake up all threads. The disadvantage is that threads in the waiting queue may starve to death, or wait a long time before acquiring the lock.

Take a look at how ReentrantLock implements fair and unfair locks:

In-depth understanding of various locks in Java (below)

Comparing the source code, we can find that fair locks have one more method to judge than unfair locks:
hasQueuedPredecessors()

 public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

What hasQueuedPredecessors() does is to determine whether the current node in the synchronization queue has a predecessor node. If it returns true, it indicates that other threads have acquired the lock earlier, so it needs to wait for the previous node to release the lock before it has a chance to continue acquiring the lock.

To sum up, fair lock is to synchronize the queue to realize that multiple threads acquire locks in the order in which they apply for locks, thereby achieving fairness. When the unfair lock is locked, the waiting in line is not considered, and the lock is directly tried to obtain the lock. Therefore, the lock is obtained first after the application is applied.

5. Reentrant lock VS non-reentrant lock

Reentrant lock: When the same object is acquired by the thread outside the method, the method that enters the inner layer of the method will automatically acquire the lock, and will not be blocked because the outer or inner method does not release the lock. In Java Both ReentrantLock and synchronized are reentrant locks. One advantage of reentrant locks is that deadlocks can be avoided to a certain extent. A simple code to explain:

public class Man {

    public synchronized void watch(){
        say();
    }

    public synchronized void say(){
        System.out.println("happy new year");
    }
}

The two methods of the Man class are decorated with synchronized. The eat() method is called in the watch () method. Because the synchronized lock is reentrant, the same thread can continue to call say () by calling the watch () method. method.
If synchronized is a non-reentrant lock, then the same thread has not released the lock (release the monitor brought by synchronized) when the watch () method is called, and it will be blocked when the say () method is called again. In fact, the current thread The lock of the object is already held, which is unreasonable anyway~ This is a reentrant lock.

Simply analyze how the reentrant lock ReentrantLock and NonReentrantLock
realize reentrant lock:

First of all, both ReentrantLock and NonReentrantLock inherit the parent class AQS, and the parent class AQS maintains a synchronization status status to count the number of reentries, and the initial value of status is 0.
When a thread tries to acquire a lock, the reentrant lock first tries to acquire and update the status value. If status == 0 means that no other threads are executing synchronization code, then the status is set to 1, and the current thread starts execution. If status != 0, judge whether the current thread is the thread that has acquired the lock, if it is, execute status+1, and the current thread can acquire the lock again. A non-reentrant lock is to directly acquire and try to update the current status value. If status != 0, it will fail to acquire the lock and the current thread will be blocked.
When the lock is released, the reentrant lock also first obtains the current status value, provided that the current thread is the thread holding the lock. If status-1 == 0, it means that all repeated lock acquisition operations of the current thread have been executed, and then the thread will actually release the lock. The non-reentrant lock is to directly set the status to 0 after determining that the current thread is the thread holding the lock, and release the lock.

6. Exclusive lock VS shared lock

Exclusive lock: The synchronized and ReentrantLock mentioned in the previous lock are exclusive locks, which means that these locks only allow one thread to access at the same time.

Shared lock: ReentrantReadWriteLock, also known as a read-write lock; multiple threads can be allowed to access at the same time, but all reader threads and other write threads will be blocked when the write thread accesses. The read-write lock maintains a pair of locks, one is a read lock and the other is a write lock. Under normal circumstances, the performance of the read-write lock will be better than the exclusive lock, because most of the scenes are read and write extra, in the case of more reading and less writing , Read-write locks have better concurrent performance and throughput than exclusive locks.

The realization principle of read-write lock will be updated in an article to analyze the source code of ReentrantReadWriteLock.

Go home for the New Year, take off~

In-depth understanding of various locks in Java (below)

Guess you like

Origin blog.51cto.com/15075523/2606414