I collated Java advanced materials for free, including Java, Redis, MongoDB, MySQL, Zookeeper, Spring Cloud, Dubbo high concurrency distributed and other tutorials, a total of 30G, which needs to be collected by myself.
Portal: https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q
Chatting with friends, he mentioned that the constructor of ReentrantLock can pass a bool data. When true, it constructs a "fair lock" and when false, it constructs an "unfair lock". My impression is that locks are not type sensitive, so I think it should be a concept invented by Java, so I made up for it.
The underlying implementation of lock
No matter what language, the lock operation at the operating system level will become a System Call. Take Linux as an example, it is a futex function, which can be understood as two functions: futex UU wait (s), which locks the variable s; futex UU wait (s) which releases the lock on S and wakes up other threads.
It is obvious in ReentrantLock that there are two types of synchronization, fair FairSync and unfair non FairSync.
The function of fair lock is to execute in strict accordance with the order in which threads are started, and other threads are not allowed to queue up for execution; instead, fair lock is allowed to queue up.
By default, ReentrantLock synchronizes through unfair locks, including the synchronized keyword, because the performance will be better.
Because it will take a long time from the thread entering the RUNNABLE state to the actual thread execution.
Moreover, after a lock is released, other threads will need to retrieve the lock again. It has gone through a series of steps: the thread holding the lock releases the lock, other threads recover from the suspend state to the RUNNABLE state, other threads request the lock, obtain the lock, and the thread executes. If a thread requests a lock directly at this time, it may avoid the consumption from suspending to resuming the RUNNABLE state, so the performance is more optimized.
/** * Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); }
By default, the ReentrantLock() used is an unfair lock. Referring to the following code again, we know that ReentrantLock obtains the lock through the decoration mode agent to sync.
/** * Acquires the lock. * * <p>Acquires the lock if it is not held by another thread and returns * immediately, setting the lock hold count to one. * * <p>If the current thread already holds the lock then the hold * count is incremented by one and the method returns immediately. * * <p>If the lock is held by another thread then the * current thread becomes disabled for thread scheduling * purposes and lies dormant until the lock has been acquired, * at which time the lock hold count is set to one. */ public void lock() { sync.lock(); }
The following is a reference to FairSync and NonfairSync's implementation of the lock method:
/** * Sync object for non-fair locks */ static final class NonfairSync extends Sync { /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } } /** * Sync object for fair locks */ static final class FairSync extends Sync { final void lock() { acquire(1); } }
When the unfair lock is used, it will immediately try to configure the status, and if it succeeds, it will jump in the queue for execution. If it fails, it will be the same as the fair lock mechanism. Call the acquire() method to acquire the lock in an exclusive way, and if it succeeds, it will return immediately. Otherwise, the thread will be added to the queue until it is called successfully.