• 十八、AQS源码解读


    一、公平、非公平锁的区别

    通过ReentrantLock的源码来讲解公平锁和非公平锁。

    公平锁与非公平锁的lock()方法唯一的区别就在于公平锁在获取同步状态时多了一个限制条件:hasQueuedPredecessors(),它是公平锁加锁时判断等待队列中是否存在有效节点的方法。

    公平锁:公平锁讲究先来先到,线程在获取锁时,如果这个锁的等待队列中已经有线程在等待,那么当前线程就会进入等待队列中。

    非公平锁:不管是否有等待队列,如果可以获取锁,则立刻占有锁对象。也就是说队列的第一个排队线程在unpark(),之后还是需要竞争锁(存在线程竞争的情况下)。

    二、lock()源码

    三、acquire()源码

    此方法是独占模式下线程获取共享资源的顶层入口。

    3.1 tryAcquire(int arg)

    此方法尝试去获取独占资源。如果获取成功,则直接返回true,否则直接返回false。

    3.2 addWaiter(Node mode)

    此方法用于将当前线程加入到等待队列的队尾,并返回当前线程所在的结点。

    private Node addWaiter(Node mode) {
        //以给定模式构造结点。mode有两种:EXCLUSIVE(独占)和SHARED(共享)
        Node node = new Node(Thread.currentThread(), mode);
    
        //尝试快速方式直接放到队尾。
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
    
        //当队列没有元素时,则通过enq创建队列
        enq(node);
        return node;
    }

    注:通过enq创建队列时,底层会默认创建一个new Node()作为伪节点,占在队列首位,第二位才是被传入的node节点。

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

    3.3 acquireQueue(final Node node, int arg)

     内部会调用tryAcquire()方法,如果获取失败,会通过parkAndCheckInterrupt()方法将队列中的Node置为等待状态,直到占用线程调用unLock()方法或中断该线程。

        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);
            }
        }
  • 相关阅读:
    Spark源码学习1.1——DAGScheduler.scala
    Spark随笔(三):straggler的产生原因
    Spark随笔(二):深入学习
    Spark随笔(一):Spark的综合认识
    Hadoop随笔(二):Hadoop V1到Hadoop V2的主要变化
    Hadoop随笔(一):工作流程的源码
    zookeeper 安装笔记 3.6.7
    OpenStack 与 大数据的融合
    三 概要模式 3) MR计数器计数 。无 reduce 计数
    五 数据组织模式 2) 分区模式 代码
  • 原文地址:https://www.cnblogs.com/shiblog/p/15788728.html
Copyright © 2020-2023  润新知