AQS解析

AQS源码解析

比如有3个线程获取锁 我们以Lock来做分析,去看AQS的源码

A B C 3个线程

A线程是第一个 会被标记为独占线程 当然默认是非公平的

setExclusiveOwnerThread(Thread.currentThread());

  exclusiveOwnerThread = thread;

 /**
     * The current owner of exclusive mode synchronization.
     独占模式同步的当前所有者。
	此时链表头部尾部没有节点
     */
    private transient Thread exclusiveOwnerThread;

B线程获取锁时会走acquire(1);

 if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){
            
                        selfInterrupt(); //线程中断
            }
            
1.分析tryAcquire(arg)
2.分析 addWaiter(Node.EXCLUSIVE))
3.分析 acquireQueued
4.分析 selfInterrupt
5. 总结

tryAcquire

//这个方法现在看起来其实就是去判断该线程是否是独占线程
 final boolean nonfairTryAcquire(int acquires) {
     
            final Thread current = Thread.currentThread(); //当前线程
     
     		//getState 可能会为0 也可能会为1
     		//0代表可以获取 1代表已被获取
     	
     
            int c = getState(); //0 
            if (c == 0) {
                //设置独占线程
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
     		
            else if (current == getExclusiveOwnerThread() //当前线程是否等于独占锁) {
                int nextc = c + acquires; //c +1  1+1=2 lock支持可重入的 重入一次+1
                if (nextc < 0) // overflow 什么时候会出现? 我觉得不会出现吧
                    throw new Error("Maximum lock count exceeded"); //超过最大锁计数 没见过
                setState(nextc); //重新设置值
                return true;
            }
            return false;
   }

addWaiter

private Node addWaiter(Node mode) {
	//mode是一个空的  用于指示节点正在独占模式下等待的标记

    Node node = new Node(Thread.currentThread(), mode); //把当前线程设置一个节点
    // Try the fast path of enq; backup to full enq on failure
    // 尝试enq的快速路径;故障时备份到完整enq

    Node pred = tail; //此时tail为空
    if (pred != null) { //这块C线程会走 
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node); //执行enq
    return node;
}

---------------------- enq -----------------------------------------------
/**
	我们来看方法的描述
	
	将节点插入队列,必要时进行初始化。见上图。
*/
    
 //当B线程进来 既是头结点也是尾结点  
 private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { 
                if (compareAndSetHead(new Node())) //设置头节点 这是第二个争抢的线程会设置为头
                    tail = head; 
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) { //设置尾结点
                    t.next = node;
                    return t;
                }
            }
        }
    }


shouldParkAfterFailedAcquire 失败后是否应暂停

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

acquireQueued

/**
	以独占不间断模式获取已在中的线程
	排队。用于条件等待方法以及获取。
*/

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;  // 失败 
    try {
        boolean interrupted = false; //中断
        for (;;) { //死循环
            final Node p = node.pred ecessor();
           	
            //在此时你会看见做判断 
            //就说明在这个节骨眼上他还有机会不被阻塞,可以获取独占资源,因为可能其他的都已经被释放了
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
           	// LockSupport.park(this); 阻塞
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;//这块唤醒会继续执行循环 但是我自己debug都是直接return了
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    } 
}

cancelAcquire 这块实际上我并没有debug到

Cancels an ongoing attempt to acquire. 取消正在进行的获取的尝试。

 //移除节点   

 private void cancelAcquire(Node node) {
    
        if (node == null)  //node节点为空
            return;

        node.thread = null; //thread等于null 

        // Skip cancelled predecessors
    	//跳过取消的前置任务
        Node pred = node.prev; //前节点
    
        while (pred.waitStatus > 0)  //前节点大于0 死循环
            node.prev = pred = pred.prev; //不太明白用意

        //predNext是要取消分片的明显节点。以下案例将
		//如果失败,在这种情况下,我们输掉了比赛与另一个取消
		//或信号,因此无需采取进一步行动。
        Node predNext = pred.next;

        //在这里可以使用无条件写而不是CAS。
		//在这个原子步骤之后,其他节点可以跳过我们。
		//以前,我们不受其他线程的干扰。
        node.waitStatus = Node.CANCELLED; //waitStatus值,指示线程已取消



    	//如果我们是尾巴,就把自己移走。
        if (node == tail && compareAndSetTail(node, pred)) {
            compareAndSetNext(pred, predNext, null);
        } else {
           //如果后继者需要信号,尝试设置pred的下一个链接
		   //所以它会得到一个。否则唤醒它传播。
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {
                unparkSuccessor(node);
            }

            node.next = node; // help GC
        }
    }


其实还有一个比较重要 什么时候被唤醒的 我想lock.unlock

把独占取消唤醒节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值