ReentrantLock源码了解
Posted qingyezhu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReentrantLock源码了解相关的知识,希望对你有一定的参考价值。
1)、ReentrantLock.tryLock //获取没有被其他线程持有的锁 //1)、当没有被任何线程持有时,首先将计数器设置为1,并设置当前持有锁的线程为当前线程,最后返回true //2)、当被当前线程持有时,将计数器加1,最后返回true; //3)、否则返回false public boolean tryLock() { return sync.nonfairTryAcquire(1); } //接着直接调用抽象类中的Sync.nonfairTryAcquire final boolean nonfairTryAcquire(int acquires) { //获取当前调用线程 final Thread current = Thread.currentThread(); //获取当前锁的状态,也就是当前锁的计数器的数值 int c = getState(); if (c == 0) { //此时说明,当前锁没有被任何线程持有 if (compareAndSetState(0, acquires)) { //使用CAS操作,更新锁的状态,即锁的计数器的数值,若是成功,则将当前锁的线程持有者设置为当前线程 setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { //根据JMM模型可知,同一个工作内存内是可见的,故同一个线程内是可见的,若相等,是同一个线程,且在同一个线程内不会发生setExclusiveOwnerThread时,在getExclusiveOwnerThread得到的不一样 //此时说明,当前锁的线程持有者是当前线程 //设置锁的计数器的值 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); //更新锁的状态,即锁的计数值的数值 setState(nextc); return true; } return false; } 2)、ReentrantLock.unlock //试图释放锁 //1)、当前线程不是该锁的持有者时,抛出异常 //2)、当前锁的计数器更改为0时,则设置当前锁的持有者为null //3)、否则,更新当前锁的状态,即锁的计数器的数值 public void unlock() { sync.release(1); } //接着直接调用抽象类AbstractQueuedSynchronizer.release public final boolean release(int arg) { if (tryRelease(arg)) { //当锁的状态为0,或者说当前锁没有持有者时,需要唤醒当前锁上挂起的线程 Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } //再接着直接调用抽象类Sync.tryRelease protected final boolean tryRelease(int releases) { //计算当前锁的计数器的数值 int c = getState() - releases; //判断当前线程是否是锁的持有者,若不是,则抛出异常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { //当计数器的数值为0,说明此时锁没有持有者了,故先更新线程持有者,之后再去更新锁的状态,这样当去获取锁的状态时,此时的锁的持有者必然是更新后的,这样锁的释放和锁的获取就能保证一致的可见性了。 free = true; setExclusiveOwnerThread(null); } //更新锁的状态,即锁的计数器的数值 setState(c); return free; } //直接调用AbstractQueuedSynchronizer.unparkSuccessor //唤醒当前节点后的第一个非取消节点中的线程 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); } 3)、ReentrantLock.lock //申请锁 public void lock() { sync.lock(); } 31)、非公平锁 //直接调用NonfairSync.lock final void lock() { //当通过CAS判断当前锁是否没有持有者,若是,则直接设置当前锁的持有者为当前线程; //否则,再次尝试加锁,最后还不成功,就如等待队列,线程挂起,直到被唤醒为止 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } //直接调用AbstractQueuedSynchronizer.acquire public final void acquire(int arg) { //尝试获取非公平锁,当失败时,就将当前线程入等待队列,线程挂起,直到被挂起 if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } //直接调用NonfairSync.tryAcquire protected final boolean tryAcquire(int acquires) { //尝试获取非公平锁 return nonfairTryAcquire(acquires); } //直接调用AbstractQueuedSynchronizer.addWaiter //将排他锁节点添加到链表尾部 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) { //当前链表已经初始化,则CAS尝试将排他锁节点更改为链表的尾节点 //设置当前节点的前一个节点为当前链表的尾节点 node.prev = pred; //当CAS尝试更新尾节点成功,则将新尾节点的前一个节点的下一个节点更新为新的尾节点 if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); return node; } //直接调用AbstractQueuedSynchronizer.compareAndSetTail //原子更新链表的尾节点 private final boolean compareAndSetTail(Node expect, Node update) { return unsafe.compareAndSwapObject(this, tailOffset, expect, update); } //直接调用AbstractQueuedSynchronizer.enq //使用CAS原子性将节点插入到链表尾部 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; //当CAS尝试更新尾节点成功,则将新尾节点的前一个节点的下一个节点更新为新的尾节点 if (compareAndSetTail(t, node)) { t.next = node; return t; } } } } //直接调用AbstractQueuedSynchronizer.acquireQueued //当当前节点为等待队列中的第一个节点时,获取到锁 final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { //当当前节点的前节点为头结点,并为当前线程尝试获取锁,成功时,设置当前节点为头结点,并将当前节点的前节点的下一个节点取消,使之没有被引用,这样可以被GC回收 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); } } //直接调用AbstractQueuedSynchronizer.setHead //设置当前节点为头结点,并将当前节点的前节点置为空,以及将当前节点持有的线程设置为空 private void setHead(Node node) { head = node; node.thread = null; node.prev = null; } //直接调用AbstractQueuedSynchronizer.shouldParkAfterFailedAcquire 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; } //直接调用AbstractQueuedSynchronizer.compareAndSetWaitStatus //尝试更新节点的状态 private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) { return unsafe.compareAndSwapInt(node, waitStatusOffset, expect, update); } //直接调用AbstractQueuedSynchronizer.parkAndCheckInterrupt //将当前线程挂起 private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
以上是关于ReentrantLock源码了解的主要内容,如果未能解决你的问题,请参考以下文章