AbstractQueuedSynchronizer源码简单分析

在分析AbstractQueuedSynchronizer时,我们先从ReentrantLock重入锁代入。

ReentrantLock主要有三个内部类:FairSync,NonfairSync, Sync
在这里插入图片描述

使用场景:

//通过这个重入锁使用场景来进入到AQS中
public class ReentrantLockTest {
    static ReentrantLock rl = new ReentrantLock();
    public static void main(String[] args) {
        for (int i = 0; i < 4; i++) {
            new Thread(()->{

                try {
                	// 1.我们从这个lock入手
                    rl.lock();
                    System.out.println(Thread.currentThread().getName()+":lock");

                    System.out.println("ThreadName="+Thread.currentThread().getName());
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    rl.unlock();
                    System.out.println(Thread.currentThread().getName()+":unlock");
                }

            },"Thread"+i).start();
        }

    }
}

我们现在来研究一下lock方法。

//1.调用ReentrantLock 的lock方法
public void lock() {
	//调用sync内部类的lock()方法
    sync.lock();
}

	// 默认调用非公平类
	/**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
         // 2.进入lock方法
        final void lock() {
            if (compareAndSetState(0, 1)) //通过cas判断当前线程status是否为0,是则将status置为1,并返回true
                setExclusiveOwnerThread(Thread.currentThread()); //当前线程获得锁
            else
                acquire(1);	//生成阻塞队列,我们在第3步对此方法进行详细分解
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
// 3 获得
public final void acquire(int arg) {
    if (!tryAcquire(arg) && //尝试获取锁
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //生产阻塞队列
        selfInterrupt();
}
//接下来!tryAcquire(arg) && //尝试获取锁
//        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
//我们做2步进行分解
//3.1 我们对3中的tryAcquire()方法进行分析
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires); //调用nonfairTryAcquire()方法
}

final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread(); //获取当前线程
            int c = getState(); //获取当前线程状态
            if (c == 0) { //当状态为0时进入
                if (compareAndSetState(0, acquires)) { //判断当前线程状态是否为0,为0则将状态设为acquires,并返回true
                    setExclusiveOwnerThread(current); //当前线程获得锁
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) { //当当前线程为锁拥有者时进入
                int nextc = c + acquires; 
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);//设置当前线程状态为c + acquires; 
                return true;
            }
            return false;
        }
}


//3.2 对acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
//我们先对addWaiter(Node.EXCLUSIVE), arg)进行分析,此处为创建双向链表
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; //tail=null
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) { //cas判断tail是否等于node的前一节点,是则将tail指向tail
            pred.next = node;	
            return node;
        }
    }
    enq(node); //自旋
    return node;
}

//3.2.1 我们对enq(node)进行分析
private Node enq(final Node node) {
    for (;;) {
        Node t = tail; //将tail赋值给t
        if (t == null) { // 初始化
            if (compareAndSetHead(new Node())) //将将head指向new Node()
                tail = head; //此时tail和head都指向new Node()
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) { //将tail指向node
                t.next = node;
                return t;
            }
        }
    }
}

下图为addWaiter双向链表的生成。
在这里插入图片描述

接下来我们对acquireQueued(addWaiter(Node.EXCLUSIVE), arg)中的acquireQueued()方法进行解析

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor(); //获得当前节点的前一节点p
                if (p == head && tryAcquire(arg)) {	//当前一节点为head,则尝试去获取锁,如果获得,则进入
                    setHead(node);//将当前节点设置为头节点
                    p.next = null; // 将p节点的next指向初始化
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) && //将状态设置为SIGNAL
                    parkAndCheckInterrupt())//将线程阻塞
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node); //如果失败,则取消
        }
    }

我写这个主要就是想分享一下双向链表生成。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值