Multithreading (3): ReentrantLock NonfairSync FairSync

structure

First look at the ReentranLock structure. It implements the Lock interface and also has three internal classes: Sync, NonfairSync, and FairSync.

(NonfairSync, FairSync)-----Inheritance-------> Sync ------Inheritance-------> AbstractQueuedSynchronizer

NonfairSync, FairSync rewrites tryAcquire of AQS 

Construction method:

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

ReentrantLock implements unfair locks by default, and only constructs fair locks when constructed as true

Nonfair.lock

ReentrantLock.class

public void lock() {
    sync.acquire(1);
}



AQS.class

public final void acquire(int arg) {
// 尝试获取不成功 并且加入队发现线程被打断了,
// 设置当前线程打断了
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

When the unfair lock is locked, the acquire of sync is called, and the acquire of sync actually inherits the acquire method of AQS.

Acquisition: try to acquire first, then join the waiting team if it fails

The final implementation of tryAcquire is the ReetranLock.Sync.nonfairTryAcquire method

 final boolean nonfairTryAcquire(int acquires) {
            // 当前线程
            final Thread current = Thread.currentThread();
            // 获取AQS状态值
            int c = getState();
            if (c == 0) {
                // 没锁,cas ,直接获取锁
                if (compareAndSetState(0, acquires)) {
                    // 将当前线程设置为锁的拥有线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                // 当前线程就是拥有锁的线程 (重入) 记录重入次数 ++
                int nextc = c + acquires;
                if (nextc < 0)
                    // overflow
                    throw new Error("Maximum lock count exceeded");
                // 更新状态值
                setState(nextc);
                return true;
            }
            return false;
        }

Join the waiting queue

acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
Node.EXCLUSIVE = null 标记 独占模式节点

private Node addWaiter(Node mode) {
        Node node = new Node(mode);

         for (;;) {
            //获取尾节点
            Node oldTail = tail;

            if (oldTail != null) {
            // 尾节点不为空 证明当前队列有值


                // 将尾节点(tail)设置为node的前节点
                node.setPrevRelaxed(oldTail);

                // cas 将尾节点设置为node
                if (compareAndSetTail(oldTail, node)) {
                    // 之前尾节点的下一个节点指向 node
                    oldTail.next = node;
                    // 处理成功 返回node
                    return node;
                }
            } else {
            // 队列为空 初始化队
                initializeSyncQueue();
            }
        }
    }


 // 初始化同步队列
    private final void initializeSyncQueue() {
        Node h;
        if (HEAD.compareAndSet(this, null, (h = new Node())))
            tail = h;
    }
final boolean acquireQueued(final Node node, int arg) {
        try {
            boolean interrupted = false;
            for (;;) {
                // 节点的上一个节点
                final Node p = node.predecessor();
                // 上一节点指向头节点 并且 再一次尝试获取 
                if (p == head && tryAcquire(arg)) {
                // 此时获取成功
                    setHead(node);
                    p.next = null; // help GC
                    // 没有被打断
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    // 尝试失败--->阻塞 ---->继续验证是否被打断
                    interrupted = true;
            }
        } catch (Throwable t) {
            // 发生了异常 取消尝试
            cancelAcquire(node);
            throw t;
        }
    }



    // 节点的上一个节点
    final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }



        // 尝试失败后是否阻塞

        private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            /*
             * 前节点已经是等待触发状态
             */
            return true;
        if (ws > 0) {
            /*
             * 前节点取消了排队
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
             // 寻找没取消的前。。。前节点

            pred.next = node;
        } else {
           // 将上一节点设置为等待触发
            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
        }
        return false;
    }

It can be seen from the source code that the author generally uses && to determine whether to proceed to the next step in programming

Recursion with an endless loop

 

1. It ends when the attempt is successful, but unsuccessful: join the queue;

2. Join the waiting queue first,

1) Queue operation:

The queue has nodes, enter the queue directly, and set the node of the day as the tail node,

The queue has no nodes, initialize an empty queue with the same head and tail as head = tail, and proceed with the above operation.

2) Try again, set the waiting state, remove the cancelled node, and judge that it is currently interrupted

Try again: If there is no previous node, that is, the head node is the previous node of the current node, try to get it again

Set the waiting state (judging the state of the previous node): waiting for trigger --> the judgment is interrupted; cancel --->set the previous node of the node to be the previous node that has not been cancelled; initial or other state --> set the previous node to wait Trigger, and then perform the above operation cycle.

The judgment was interrupted:

 

Guess you like

Origin blog.csdn.net/qq_22420441/article/details/86500017