The coder is on the ropes

Only the end of the heart, the journey of the scenery has been lost half, the heart just want to see the scenery, far from the end of the half!

ReentrantLock Fair and unfair locks

ReentrantLock is an exclusive lock, which is implemented based on AQS. If a thread acquires the lock, it will be blocked when another thread attempts to acquire the lock. ReentrantLock can be used in two ways: FairLock and NoFairLock. ReentrantLock defaults to an unfair lock. The following explains fair and unfair locks.

Fair lock

Fair lock means any threads want to acquiring a lock, will have to wait in line, just as you go to the dining hall meal, has the quality of the students are standing in line, as follows, the benefits of using a fair lock is a thread is in accordance with the order of the first come, first processing, ensure that all threads are able to get the lock, but the efficiency will be low.

Not fair lock

An unfair lock means that you don’t have to queue to get the lock, just like in the canteen, those bullying students don’t queue, directly rush to the first, the advantage of using an unfair lock is relatively high efficiency, but it will lead to some threads have not been able to get the lock, ReentrantLock default is unfair lock.

You can use the constructor to set fair and unfair ReentrantLock, which defaults to fair

public ReentrantLock(a) {
    sync = new NonfairSync();
}
Copy the code

The constructor is true for a fair lock and false for an unfair lock

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
Copy the code

Already the principle

ReentrantLock is implemented based on AQS, the core of which is the processing of state. As for state, we can see the detailed explanation of AQS in the last article. We mainly look at the implementation methods of fair lock and unfair lock.

The thread first tries to acquire the lock, finds the state, changes the state to 1 through CAS, and then returns. If the thread finds that the state is not 0 when acquiring the lock, it proves that the lock has been held by another thread, so it is added to the end of the AQS queue, and then suspended. When the thread that obtained the lock releases the lock after completing its task, It will wake up the queue head node, and then the queue head thread to execute the task, it can be seen that the execution of threads is sequential, according to the PRINCIPLE of FIFO first in first out.

Attempt to acquire a lock

Joins the AQS queue because the lock is already held by another thread

The following code adds a thread to the end of the queue by enclosing a node of type EXCLUSIVE.

private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if(pred ! =null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }
Copy the code

16. For a fair lock, it chiefly determines whether the first thread in the AQS queue is the current thread by hasqueued24 (), while for a non-fair lock it does not determine whether the first thread in the AQS queue can seize the lock, whether it is located in the queue capital. Why should it determine, because a fair lock requires that each thread be executed in sequence, If the current thread is at the head of the queue, the lock is acquired; if the head of the queue is not the current thread, the queue is queued.

public final boolean hasQueuedPredecessors(a) {
    Node t = tail;
    Node h = head;
    Node s;
    returnh ! = t && ((s = h.next) ==null|| s.thread ! = Thread.currentThread()); }Copy the code

The current thread attempts to acquire the lock to determine if it is at the head of the AQS queue

At the head of the queue and thread A releases the child lock, thread B acquires the lock directly.

Already use

ReentrantLock only needs to lock the code segment that needs to be synchronized. It needs to wrap the code ina try and release the lock in finally.

public class ReentrantLockTest {
    private final ReentrantLock lock = new ReentrantLock();
    public void add(a){
        lock.lock();
        try {
            System.out.println("get data");
        }finally{ lock.unlock(); }}}Copy the code

That’s all for today’s sharing, thank you for watching, next time.