java_Lock【AQS】

AQS

AQS的核心也包括了这些方面:同步队列,独占式锁的获取和释放,共享锁的获取和释放以及可中断锁,超时等待锁获取这些特性的实现

1.同步队列

AQS中的同步队列则是通过链式方式进行实现(双向链表没一个节点都拥有前驱和后继节点),使用头尾指针的方式管理同步队列。
获取锁失败进行入队操作,获取锁成功进行出队操作。

2.独占锁

(1)获取独占锁【acquire方法】
调用lock()方法获取独占锁,获取失败就将当前线程加入同步队列,成功则线程执行,实际上Lock()方法会调用AQS的acquire()方法
A.成功则方法结束返回
B. 失败则先调用addWaiter() 然后调用acquireQueued()方法进入同步队列等待
(2)获取失败进入等同步队列

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

当前线程的信息存放到一个新的Node节点,当前链表尾节点不为空直接进行尾插入,compareAndSetTail是一个CAS操作操作失败会进入自旋进行重试,
如果当前队列为null执行enq操作

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

enq操作视为当前没有队列
1.重新穿件一个头结点 t
2.当t==null执行插入
(3)acquireQueued()方法 排队获取锁
1.获取当前及诶单的先驱节点
2.判断当前节点的先驱节点势头及诶单并且成功获取同步状态,即可以获取独占锁
3.将队列的头指针指向当前节点
4.释放前驱节点 (前驱节点已经获取独占锁)
5.获取失败 进入等待状态继续获取独占锁

总结

在这里插入图片描述
图片来源:https://juejin.im/post/5aeb07ab6fb9a07ac36350c8
1.线程获取锁失败,线程被封装成Node进行入队操作,核心方法在于addWaiter()和enq(),同时enq()完成对同步队列的头结点初始化工作以及CAS操作失败的重试;
2.线程获取锁是一个自旋的过程,当且仅当 当前节点的前驱节点是头结点并且成功获得同步状态时,节点出队即该节点引用的线程获得锁,否则,当不满足条件时就会调用LookSupport.park()方法使得线程阻塞;
3.释放锁的时候会唤醒后继节点;

3.可中断获取锁(acquireInterrutibly)
public final void acquireInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
		//线程获取锁失败
        doAcquireInterruptibly(arg);
}

判断获取所失败则会调用doAcquireInterruptibly
将当前节点同步到队列中
循环获取队列的头结点出队,获取成功将当前头结点移动下节点

4.超时等待获取锁(tryAcquireNanos)

1.在超时时间内,当前线程成功获取了锁;
2.当前线程在超时时间内被中断;
3.超时时间结束,仍未获得锁返回false。

public final boolean tryAcquireNanos(int arg, long nanosTimeout)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    return tryAcquire(arg) ||
		//实现超时等待的效果
        doAcquireNanos(arg, nanosTimeout);
}

doAcquireNanos
1.根据超时时间和当前时间计算出截止时间
2.当前线程获得锁出队列
3.重新计算超时时间
4.线程阻塞等待
5.线程中断抛出异常

5.共享锁(acquireShared)
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}

tryAcquireShared返回一个int类型大于等于0成功获取锁 小于零获取失败执行doAcquireShared() 与独占锁类似获取当前队列判断是否为null将获取锁对象的线程变为Node,尾插入队列成功进入同步队列失败则CAS自旋
进入同步队列之后若为投机诶单则获取同步状态,不为头则插入等待获取

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值