zoukankan      html  css  js  c++  java
  • ReentrantLock源码学习总结 (二)

    ReentrantLock 示例

        private ReentrantLock lock = new ReentrantLock(true);
    
        public void f(){
            try {
                lock.lock();
                //do something
            }
            finally {
                lock.unlock();
            }
        }
    

    源码解析(公平锁-unlock流程)

    ReentrantLock#unlock()

    	public void unlock() {
            sync.release(1);
        }
    

    AbstractQueuedSynchronizer#release(int arg)

     	public final boolean release(int arg) {
            //尝试释放锁,只有当 state == 0 才会释放成功
            if (tryRelease(arg)) {
                //释放成功之后,查看head节点,如果head节点不为 null,并且,head节点不为0 (可能为 -1)
                Node h = head;
                if (h != null && h.waitStatus != 0)
                    //unpark 线程
                    unparkSuccessor(h);
                return true;
            }
            return false;
        }
    

    ReentrantLock.Sync#tryRelease(int arg)

      protected final boolean tryRelease(int releases) {
          		//state - releases,上锁之后,state > 0,所以释放锁要减掉
                int c = getState() - releases;
          		//如果当前线程并不是持有锁的线程,不能乱释放锁,直接给你抛个异常
                if (Thread.currentThread() != getExclusiveOwnerThread())
                    throw new IllegalMonitorStateException();
            	//释放标志
                boolean free = false;
          		//由于是可重入锁,所以当 c == 0 的情况下才真正释放完成
                if (c == 0) {
                    free = true;
                    //设置当前线程为空
                    setExclusiveOwnerThread(null);
                }
                setState(c);
                return free;
            }
    
    

    AbstractQueuedSynchronizer#unparkSuccessor(Node node)

    	private void unparkSuccessor(Node node) {
            //获取head node节点的 waitStatus , < 0(-1) 就CAS 改回 0
            int ws = node.waitStatus;
            if (ws < 0)
                compareAndSetWaitStatus(node, ws, 0);
    		//找到下一个节点
            Node s = node.next;
            //如果下一个节点为null,或者 已经取消抢锁了,继续往下找
            if (s == null || s.waitStatus > 0) {
                s = null;
                //从尾部向前遍历,如果 waitStatus<=0 就赋值给 s,这样保证最前边的一个waitStatus<=0的线程可以唤醒。
                for (Node t = tail; t != null && t != node; t = t.prev)
                    if (t.waitStatus <= 0)
                        s = t;
            }
            //如果下一个节点不为 null,直接 unpark 线程,对应代码就是AbstractQueuedSynchronizer#acquireQueued(Node node, int arg) 中 的for(;;),这样线程唤醒之后,就会尝试再去获取锁了。
            if (s != null)
                LockSupport.unpark(s.thread);
        }
    

    总结

    释放锁的流程比较简单,就是讲 state减去1,然后去队列里面找下一个节点,最后执行 unpark 方法唤醒线程。

  • 相关阅读:
    geoserver发布mysql表数据
    geoserver1
    geoserver
    快速搭建arcgis以及cesium环境
    openlayers和cesium实现地图二三维切换
    记Mysql类型引起的BUG
    OpenLayers 图层(Layers) 详解
    基于TrueLicense实现产品License验证功能
    第七章
    第六周进度报告
  • 原文地址:https://www.cnblogs.com/panzi/p/11690129.html
Copyright © 2011-2022 走看看