AQS ,ReentrantLook 实现的公平锁加锁过程源码分析记录。

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

只是一篇源码分析记录,写的并不详细,建议自己debug源码查看。

在计算机科学中,比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令 ,很多高性能的无锁算法就是基于这种方式实现。

	//这四个参数的意思是 this对象中 的valueOffset如果是expect那么更新成update
  public final native boolean compareAndSwapInt(this, valueOffset, expect, update);

在锁框架中,AbstractQueuedSynchronizer 它提供了一个基于FIFO队列(本质就是双向链表),可以用于构建锁或者其他相关同步装置的基础框架,ReentrantLook是基于它构建的。

以ReentrantLook中的公平锁为例,分析公平锁获取锁的过程。释放锁  非公平锁 先暂时不在此分析。

 abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();
       //省略......
}

可以看到   ReentrantLook内部类Sync集成了抽象类AQS 。公平锁实现中 FairSync又继承了Sync

	/**
     * Sync object for fair locks
     */
	 //公平锁 代码在ReentrantLook中
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
	
        final void lock() {
			//获取锁
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }
	
	//代码在AbstractQueuedSynchronizer中
	 public final void acquire(int arg) {
		//尝试获取锁 ,如果获取失败  就将当前线程放入队列中 等待唤醒
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
	
	
        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
		 //检测是否可以获取到锁  递归调用(也就是所说的重入锁 ),第一个 ,没有等待的  可以获取锁。
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
			//获取当前锁的状态 如果为0则当前锁没有人获取
            if (c == 0) {
				//既然是公平锁 就要先检查队列是是否有等待的
                if (!hasQueuedPredecessors() &&
					//如果队列中没有等待的 那么在获取一下 成功则获取到锁  失败则可能是有人比自己抢先一部
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
			//查看当前获取锁的是否就是自己  是的话则state加1 
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }
	
	//代码在ReentrantLook中 既然没有获取到锁  首先将当前线程组装成链表的一个节点(队列)
	 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;
    }
	//代码在ReentrantLook中 这段代码的意思是 循环
	  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;
                }
            }
        }
    }
	
	 //这个方法是真正的获取锁
    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);
        }
    
	//代码在AbstractQueuedSynchronizer中
	 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 {
            /*
			 * 走到了这里说明自己的前驱很可能是0 就测试一下 如果是0就设置成-1  0是初始状态
             * 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;
    }
	//代码在AbstractQueuedSynchronizer中 如果自己的前驱是正常状态 自己就可以挂起 等待自己的前驱节点唤醒
	   private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }
	

这就是ReentrantLook提供的公平锁中加锁的过程。

-------------------------尽力而为------------------------------

参考:文章基于JDK8源码分析

转载于:https://my.oschina.net/wang520/blog/2998053

你可能感兴趣的:(AQS ,ReentrantLook 实现的公平锁加锁过程源码分析记录。)