ReentrantLock unfair lock exactly how unfair

Reentrant lock key areas:

1: Use of unsafe manner AQS cas member variables of state "atoms plus one" operation.

2: if the current thread repeatedly lock, equivalent to an operating state continue to increase on the basis of the original value; releasing the lock condition is "atomic minus one" reaches zero.

3: ReentrantLock equity in non-locking problems:

Strictly speaking not entirely unfair, when the thread is not to get locked into a thread Node list, and the list with multiple nodes under circumstances still have to queue park, pioneer node waiting list to go after unPark to continue.

Rather than equity is locked when the first attempt did not go ignored threads waiting list later if the first attempt fails, it will try to determine whether the lock is released, if the current lock has been released, two tries locked when still ignore other threads waiting list, will directly try shackles.

4: focus on a fair lock in hasQueuedPredecessors methods:
(1) if the list is not created, try to direct resource locking;
(2) if the next node of the list head node is null, attempts to directly lock (actually the current thread re-entry);
(3) if the current thread and the thread holding the lock is the same thread, but also directly lock (actually the current thread re-entry);

 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());
    }

ps: the list is relatively clever design, the head node either node holding the lock, either Tread data field is null nodes. Because for the first time in the current resource is not locked into the waiting list, the author out of a virtual "replacement node", once the first lock is finished, it will remove the "alternative node" so true node holding the lock become the head node list.

 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());
    }

5: After the wait list process locked:

When a node into the team, the method returns the node object;
(1) if it is found before a current node is the first node, then the current thread immediately try once locked, without waiting for the head node active unPark, of course, will head node be unPark; if the lock fails to determine whether the Signal previous node status, and if the state of the current thread will be cut off in their own park, waiting wake pioneer node. If the node is not a pioneer Signal but CANCELLED, has been looking forward along the linked list until you find the Signal will link itself to the back of the node.

 final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

(2) if the node is not a head node precursor, then direct execution logic is interrupted.

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

Summary:
As can be seen locking mechanism ReentrantLock 1.6 previous sync keywords are lightweight compared to:
(1) when only one thread is locked, no other threads situation of resource consumption, it does not initialize the waiting list, only a very lightweight CAS operations.
(2) and ReentrantLock support for the same resource repeatedly locked.
(3) even if there is a queue, the queue waiting for the first thread node object, will take the initiative to try to lock.

Guess you like

Origin www.cnblogs.com/zzq-include/p/11995473.html