ReentrantLock有感

·  阅读 94

模拟多线程加锁情景 ReentrantLock 默认是非公平锁

ReentrantLock lock = new ReentrantLock();
线程1  lock.lock();
执行compareAndSetState(0, 1),此时state=0,所以CAS成功,state=1,并将当前占有线程设为线程1

final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
        
此时 线程2 也 lock.lock();
执行compareAndSetState(0, 1) 发现state=1了,不为0,所以CAS失败,走acquire(1)方法。

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
因为是非公平锁,还会去尝试加锁,但此时线程1正独占着锁,加锁失败。走acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法,先看addWaiter(Node.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;
    }
先创建了当前线程2的一个Node对象,此时tail指针为空,pred指针指向tail也为空,走enq(node)方法 

private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }
看到了一个无限for循环。。 t指针指向tail都为空,走 compareAndSetHead(new Node()),创建一个空的Node结点并将Head指针指向空Node,把tail指针也指向空Node。然后进入下一次循环,t指针指向tail,即t指针也指向空Node,t!=null,线程2Node的prev指针指向空Node,tail指针指向线程2Node,空Node的next指针指向线程2Node,返回 空Node。此时形成了空Node和线程2Node的双向链表结构

下面再来看acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法
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);
        }
    }
又是个无限for循环。。p指针指向线程2Node前面那个空Node结点,p==head为true,此时又将尝试加锁,加锁失败后走shouldParkAfterFailedAcquire(p, node) 方法

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 {
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

空Node的waitStatus=0,ws=0,走compareAndSetWaitStatus(pred, ws, Node.SIGNAL)方法,就是把空Node结点的waitStatus设为SIGNAL,并返回false。进入下一次for循环,再次进入这个方法,此时ws == Node.SIGNAL成立,返回true。执行parkAndCheckInterrupt()方法

private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}
意思就是把当前线程2挂起,阻塞等待。线程2的lock过程就卡在 LockSupport.park(this);这一步上了。

下面我们来看线程1释放锁会发生什么:
public void unlock() {
    sync.release(1);
}

public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
 
protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        } 
走到tryRelease(1) c=1-1=0,线程1就是当前占有线程,执行 setExclusiveOwnerThread(null);将当前占有线程设为null,setState(0),return true。
接着走这里的代码
if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
h指针指向head,即指向空Node,空Node的waitStatus=SIGNAL,不为0,走unparkSuccessor(h);

private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }
compareAndSetWaitStatus(node, ws, 0);将空Node的waitStatus设为0,s指针指向线程2Node,执行 LockSupport.unpark(s.thread); 将线程2唤醒
这里线程1释放锁过程结束。就是将当前占有线程设null,设state=0,并将队头线程2唤醒

此时线程2
private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.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;
            }
线程2将去尝试获取锁了,如果获取成功

private void setHead(Node node) {
        head = node;
        node.thread = null;
        node.prev = null;
    }
将head指针指向线程2Node,并将Node设为空,将原空Node去掉

就先说到这吧。。
复制代码
分类:
阅读
标签: