JDK1.8 AbstractQueuedSynchronizer的实现分析(学习笔记)

【jdk17-AbstractQueuedSynchronizer翻译】 类说明 提供了一个实现阻塞锁及相关同步器(信号量(semaphores)、事件(events)等)的框架,这些同步器依赖于先进先出(FIFO)等待队列该类主要为了大多数同步器的有用的基础工具而设计,这些同步器基于一个表征状态(represent state)的单个原子int值。子类必须定义改变该状态的受保护(protected)方法,并且定义该状态在对象被获取或释放时的意义。给定这些方法,此类中的其他方法负责所有的排队和阻塞机制。子类可以维护其他状态字段,但只有使用 #getState、#setState 阅读详情

lock方法会调用acquire方法,该方法在AQS中实现

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

正常使用一个ReentrantLock 的lock() 方法时,在不能获得所得情况下,该方法是阻塞的,对吧
以上acquire方法拆解一下方法调用
首先tryAcquire(arg),英语不好的我Acquire,百度给出的意思是获得,获取,那么好这里可以给成意思是尝试获得的意思?
如果申请资源失败,则返回false,那么会先调用addWaiter(Node.EXCLUSIVE),这里的Node.EXCLUSIVE代表独占的意思,so这个节点是独占的?

/**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    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) { //如果当前链表有尾节点,就把封装当前线程的节点追加到尾部?这里的尾节点操作也是CAS的
            node.prev = pred; 
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        // 如果没有等待的线程(节点列表为null),则初始化头尾节点,该方法是一个自旋的方法
        enq(node);

        return node;
    }

这里考虑多线程调用的情况,这里的链表不存在线程安全问题,因为对每个头尾节点的操作都是CAS的。详见代码片段里的
compareAndSetHead和compareAndSetTail方法。

/**
     * Inserts node into queue, initializing if necessary. See picture above.
     * @param node the node to insert
     * @return node's predecessor
     */
    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            //第一次的时候尾节点肯定是一个 null,则初始话一个空内容节点为头节点,第二次循环时尾节点已经不是null了
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t; //将node节点的前驱节点设置成尾节点,即先尝试追加到链表的尾部,如果尾节点是t,则将尾节点设置成node,退出循环
                if (compareAndSetTail(t, node)) { 
                    t.next = node;
                    return t;
                }
            }
        }
    }

所以第一个等待锁的线程A在AQS中的数据结构是这样的?

空节点 -> node(name:A)

看到这里,AQS中对内部链表的头尾操作都是CAS的,所以链表中的节点排序也是完全按照申请锁的顺序排列的。addWaiter方法的操作无非是将线程封装为一个node,追加该节点到链表的尾节点,然后addWaiter 方法返回封装好的node方法,继续调用acquireQueued(node) ,
acquireQueued 方法是一个自旋的方法,假设当前只有一个线程A排队申请锁,目前链表形式为。

空节点 -> node(name:A)

/**
     * Acquires in exclusive uninterruptible mode for thread already in
     * queue. Used by condition wait methods as well as acquire.
     *
     * @param node the node
     * @param arg the acquire argument
     * @return {@code true} if interrupted while waiting
     */
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {//自旋方法
                final Node p = node.predecessor();
                //获得p的前驱节点,并判断是否为head节点,如果为head节点且成功获取到资源,就将当前线程节点设置成队列的头节点,并返回
                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);
        }
    }

这里判断p==head,如果node的前驱节点是head,说明该节点排成了老二,而老二如果成功获取到资源,则变成老大,那么这里老大的起到的是什么作用?
>

我的程序有一把锁在外边阻塞中(sleep),从代码上看一开始tryAcquire方法就成功申请到资源,就不会有他的node维护在这里,就是说他的锁不需要在这里排队?那么后续的unlock是怎样的一个机制?
因为锁在别的线程中持有(state>0),所以这个acquireQueued方法中的tryAcquire会返回false
然后shouldParkAfterFailedAcquire,字面意思如果申请资源失败则判断是否可以挂起线程

/**
     * Checks and updates status for a node that failed to acquire.
     * Returns true if thread should block. This is the main signal
     * control in all acquire loops.  Requires that pred == node.prev.
     *
     * @param pred node's predecessor holding status
     * @param node the node
     * @return {@code true} if thread should block
     */
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        //获取节点的前驱节点等待状态
        int ws = pred.waitStatus;
        //如果是SIGNAL状态,返回true,第一次来这个肯定不会成立,因为是node的前驱节点是一个空节点。
        //空节点->node(A)
        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) { //Node.CANCLED 如果节点是被放弃的(什么情况下会放弃,中断么??)
            /*
             * 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.
             */
            //将前驱节点的状态设置成SIGNAL
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

至此针对我的测试,这个方法会走compareAndSetWaitStatus(pred, ws, Node.SIGNAL); 分支,所以目前node(name:A)节点的前驱(head节点)的waitStatus状态为 SIGNAL,该方法的第一次调用会返回false
目前针对线程A的链表表示

node(waitStatus:SIGNAL)->node(name:A)

因为shouldParkAfterFailedAcquire返回了false,所以不会调用parkAndCheckInterrupt,那么会进入第二次循环。
node的前驱节点是head 这个是毫无疑问的,但是就是因为获取锁的线程还是一个熊孩子,没有释放资源(state>0)
所以依旧会调用shouldParkAfterFailedAcquire方法,但此时方法内部已经不一样了,这里已经开始满足第一个条件分支了,所以此方法此次会返回true,因为因为shouldParkAfterFailedAcquire返回了true,所以会接着调用parkAndCheckInterrupt()方法
该方法实现如下:

 /**
     * Convenience method to park and then check if interrupted
     *
     * @return {@code true} if interrupted
     */
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);//调用park()使线程进入waiting状态
        return Thread.interrupted();//如果被唤醒,查看自己是不是被中断的。
    }

LockSupport.park(this); 大神说park()会让当前线程进入waiting状态。在此状态下,有两种途径可以唤醒该线程:1)被unpark();2)被interrupt()。
如果当前线程waiting了,那么就不会有第三次循环了….因为当前线程已经waiting了……
这里阻塞的线程应该是申请锁的线程,LockSupport.park(this);参数的作用是对应的blocker会记录在Thread的一个parkBlocker属性中,通过jstack命令可以非常方便的监控具体的阻塞对象.

如果此时又有一个线程B,按照此逻辑继续申请一把锁,按AQS的处理逻辑会维护成如下形式

node(waitStatus:SIGNAL)->node(name:A)->node(name:B)

假设tryAcquire(arg)依旧失败,state依旧不给释放,熊孩子还不还,那么对于node(name:B) 来说,在acquireQueued中他的前驱肯定不是head节点,所以他只能走shouldParkAfterFailedAcquire方法设置前驱节点的状态,然后调用parkAndCheckInterrupt()方法,去阻塞当前当前申请锁的线程。
同上经历2次自旋后在AQS中链表的维护成如下形式

node(waitStatus:SIGNAL)->node(name:A,waitStatus:SIGNAL)->node(name:B)

这里贴一个大神的总结和图

再来总结下它的流程吧:
调用自定义同步器的tryAcquire()尝试直接去获取资源,如果成功则直接返回;
没成功,则addWaiter()将该线程加入等待队列的尾部,并标记为独占模式;
acquireQueued()使线程在等待队列中休息,有机会时(轮到自己,会被unpark())会去尝试获取资源。获取到资源后才返回。如果在整个等待过程中被中断过,则返回true,否则返回false。
如果线程在等待过程中被中断过,它是不响应的。只是获取资源后才再进行自我中断selfInterrupt(),将中断补上。
由于此函数是重中之重,我再用流程图总结一下:
图

现在AQS的链表里有三个节点。

node(waitStatus:SIGNAL)->node(name:A,waitStatus:SIGNAL)->node(name:B)

假设一开始长时间阻塞不还锁的线程,时间到了玩够了回家吃饭去,线程中调用了reentrantlock.unlock(); 方法,他玩够了我这边两个兄弟还在那waiting呢,是不是会释放他的线程标志
释放锁的代码也是很简单的

    public void unlock() {
        sync.release(1);
    }

这里sync是实现AQS的一个内部类Sync的实例,所以本质上还是在调用AQS的功能,看看怎么做的。

 /**
     * Releases in exclusive mode.  Implemented by unblocking one or
     * more threads if {@link #tryRelease} returns true.
     * This method can be used to implement method {@link Lock#unlock}.
     *
     * @param arg the release argument.  This value is conveyed to
     *        {@link #tryRelease} but is otherwise uninterpreted and
     *        can represent anything you like.
     * @return the value returned from {@link #tryRelease}
     */
    public final boolean release(int arg) {
        if (tryRelease(arg)) {//释放资源
            Node h = head; 
            if (h != null && h.waitStatus != 0) //头结点不为null,且头结点是有状态的?
                unparkSuccessor(h);//唤醒等待队列里的下一个线程
            return true;
        }
        return false;
    }

由上文得知,调用AQS的acquire(int args)方法,会调用子类的tryAcquire(int args)实现从而实现对线程状态的重置,那么这里有一个tryRelease(arg) 是不是也是子类的一个实现呢?其实就是调用的子类实现,依旧不去管他的实现
暂且把tryRelease当作释放资源,如果释放成功则将头节点做为参数,调用unparkSuccessor方法。

/**
     * Wakes up node's successor, if one exists.
     *
     * @param node the node
     */
    private void unparkSuccessor(Node node) { //这里参数是头结点。
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;//判断节点的等待状态
        if (ws < 0)  //如果当前节点是有状态的,清除状态
            compareAndSetWaitStatus(node, ws, 0); //置零当前线程所在的结点状态,允许失败。

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        Node s = node.next; //拿到链表中的第二个节点,本例是node(name:A,waitstatus:SIGNAL) 
        if (s == null || s.waitStatus > 0) { //如果没有第二个节点或者第二个节点的状态为取消
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)  //从尾节点开始向前找有状态的节点并返回
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread); //唤醒线程
    }

依据上面的逻辑本例中的node(name:A,waitstatus:SIGNAL) 节点所持有的线程将得到释放。但是这个节点并没有被移除。AQS中的链表结构变成了这样

node(waitstatus:0)->node(name:A,waitstatus:SIGNAL)->node(name:B)

此时线程A将得到唤醒,然后他会继续做final boolean acquireQueued(final Node node, int arg) 方法中的自旋。为方法继续把acquireQueued的代码拿出来再贴一遍

/**
     * Acquires in exclusive uninterruptible mode for thread already in
     * queue. Used by condition wait methods as well as acquire.
     *
     * @param node the node
     * @param arg the acquire argument
     * @return {@code true} if interrupted while waiting
     */
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {//自旋方法
                final Node p = node.predecessor();
                //获得p的前驱节点,并判断是否为head节点,如果为head节点且成功获取到资源,就将当前线程节点设置成队列的头节点,并返回
                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);
        }
    }

此时线程A发现他的前驱节点为head,并且此时再申请资源tryAcquire(arg) ,因为那个熊孩子把资源释放了,所以此时申请资源是成功的,然后会将当前节点设置为链表的头结点,并释放原来的头结点占用的内存。
这样链表结构就成了这个样子:

node(name:A,waitstatus:SIGNAL)->node(name:B)

针对线程A来说acquireQueued 方法已经执行完成,假设我们一直老老实实的等没有通知中断线程,则线程A中的代码行reentrantLock.lock() 方法将返回,一个代码行执行完成,会接着执行下一个代码行,lock() 加锁成功了!那么问题来了(问题和挖掘机没有任何关系)tryAcquire和tryRelease 到底在争抢和释放什么东西?
继续看tryAcquire方法在ReentrantLock类中的实现(公平锁)

   /**
           * 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();
              //getState来自AQS,放方法取AQS中的全局变量state 注意是全局
              int c = getState();
              if (c == 0) { //AQS中默认state值为0,如果为0应该可以证明当前AQS队列里的线程没有修改过state,也就是说没有人持有锁
                  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;
          }

可以发现tryAcquire 方法会先获取AQS中的全局变量,也可以说AQS维护的链表中的所有节点都会去检查state这个变量,所以这个state是一个线程状态,也可以看作是他们在抢的一把锁,如果发现state为0,则代表竞争到资源,并通过CAS的方式设置该值为1,然后设置当前线程为exclusiveOwnerThread,另一个条件因为锁是可重入的啊老铁
这里有一个hasQueuedPredecessors() 方法,参照某大神所说

正如hasQueuedPredecessors的注释所说,该方法的作用是为了避免 “线程闯入”,即对于ReentrantLock来说,即便是state为0时,AQS队列中也可能是有节点的(被取消的,打断的节点)等等,这个时候为了保证AQS队列的公平性,不再尝试加锁,而是返回false,到AQS的队列中去排队。所以,这也是该方法被用在公平锁中的原因。

遗留问题:
1.为什么用链表管理线程
2.节点的状态SIGNAL 主要含义
3.在AQS中的线程如何响应中断,中断策略是什么?

   /** waitStatus value to indicate thread has cancelled */
    static final int CANCELLED =  1;
    /** waitStatus value to indicate successor's thread needs unparking */
    static final int SIGNAL    = -1;
    /** waitStatus value to indicate thread is waiting on condition */
    static final int CONDITION = -2;
    /**
     * waitStatus value to indicate the next acquireShared should
     * unconditionally propagate
     */
    static final int PROPAGATE = -3;

引用:
https://www.cnblogs.com/waterystone/p/4920797.html

Java的AQS详解1--独占锁的获取及释放 其实,很早之前就写过一篇浅谈Java的AQS,当时对AQS的运作机制有了大致的掌握,但可能源码还是没完全吃透,有些细节还是云里雾里。 最近又过了一遍AQS源码,觉得体悟更深了些,怕时间久了遗忘掉,记录下来方便后面查阅。 为避免篇幅较长,将这部分2篇来讲解,本文为第1篇,主要讲解AQS独占锁的获取及释放。 加锁 独占锁加锁的方法入口为acquire(int arg); public final void acquire(int arg) { if (!tryAcquire(arg) && 阅读详情

相关推荐

汇丰外包Java岗面试复盘:Zoom面1.5小时,从英语、粤语到现场敲代码的极限挑战

本文详细记录了汇丰银行外包Java岗位的面试全过程,包括多语言切换(英语、粤语)的技术沟通挑战和现场编码测试的实战经验。从高并发编程到JVM调优,面试不仅考察技术深度,更注重实战问题解决能力。文章分享了应对跨国银行技术面试的实用策略,帮助Java开发者在跨文化环境中提升竞争力。

weixin_42524824的博客 362

parkAndCheckInterrupt

使用LockSupport.park挂起当前线程编程WATING状态 Thread.interrupted,返回当前线程是否被其他线程触发过中断请求,也就是thread.interrupt();如果有触发过中断请求,那么这个方法会返回当前的中断标识true,并且对中断标识进行复位标识已经响应过了中断请求。如果返回true,意味着在acquire方法中会执行selfInterrupt()。 private final boolean parkAndCheckInterrupt() { LockSu.

Leon_Jinhai_Sun的博客 1775

[漏洞利用]利用五次Shift越权破解win7\win10开机密码

注:第一个学习和接触的Windows漏洞 文章目录本机实验环境前置知识漏洞原理漏洞介绍漏洞验证解决方法基本流程介绍详细步骤截图 本机实验环境 虚拟机:VMware Workstation 14 pro 操作系统:Windows10 前置知识 1、cmd工具路径 c:\windows\system32\cmd,按五次shift默认调用同目录下sethc文件,其路径为“c:\windows\system32\sethc.exe” 2、用户/账户密码存储位置 c:\windows\system32\config\

Y4tacker的博客 2万+

ReentrantLock中acquireQueued关于挂起,中断的一些理解

熟悉ReentrantLock获取锁流程的小伙伴们应该能看懂下面的步骤,如果不熟悉的话可能会有点懵 acquireQueued在acquire方法里,当获取锁失败时会进入此方法 当shouldParkAfterFailedAcquire()返回true的时候,会进入parkAndCheckInterrupt()方法 parkAndCheckInterrupt()方法: 看到LockSupport.park(this)进行了线程的挂起,这里不讨论底层如何实现挂起的 现在关注关于int

weixin_40208575的博客 4042

STM32与HT7038的高精度电能计量系统设计与实现

本文详细介绍了基于STM32微控制器与HT7038三相电能计量芯片的高精度电能计量系统设计与实现。文章从项目选型出发,深入剖析了硬件电路设计、SPI驱动开发、芯片校准及系统集成等关键环节,为智能电表、能源监控等应用提供了高性价比且稳定的国产化解决方案。

pytorch8learner的博客 389

HBuilderX结合Android Studio实现Uniapp安卓Apk高效离线打包指南

本文提供了一份详细的Uniapp安卓Apk离线打包实战指南。通过整合HBuilderX与Android Studio,手把手教你搭建本地编译环境、配置原生工程、执行核心打包流程,并分享快速更新资源和排查常见问题的技巧,助你彻底摆脱云端打包的排队依赖,实现高效、可控的应用构建。

weixin_28835551的博客 551

AQS源码解析---独占锁获取

一 简介 AQS(AbstractQueuedSynchronizer)是java并发工具的基础,底层很多实现都采用了CAS乐观锁的方式,在锁获取冲突时,通过自旋重试来轻量的获取锁(synchronized的可重入锁、轻量级锁和重量级锁也有CAS操作,我理解目的都是尽可能的减少获取锁带来的上下文开销)。 AQS是一个抽象类,但是没有抽象方法。这样子类可以根据自己的需要实现对象的方法,而不用实现所有的方法,未实现的方法会默认抛出UnsupportedOperationException异常。 ..

xad669475795的博客 729

深入解析uncompyle6反编译pyc文件及常见错误修复指南

本文深入解析了使用uncompyle6工具反编译Python字节码文件(.pyc)的完整流程。针对实践中最高频的KeyError和Python版本范围限制两大错误,提供了详细的修复方案与步骤指南,并分享了处理复杂反编译结果的高级技巧与安全实践,是进行代码恢复、调试与分析的重要参考。

uber9的博客 534

并发核心技术总结(四)

start()和run()方法源码 start()方法其实是通过start0()方法启动线程的 public synchronized void start() { // 如果线程不是"就绪状态",则抛出异常! if (threadStatus != 0) throw new IllegalThreadStateException(); // 将线程...

Kim_ 238

OpenWRT使用4G/5G无线网卡模块上网

将4G/5G开发板插入设备,终端输入lsusb或lspci,看设备是否识别到4G/5G模块。

1万+

[STC32G144K246入门第三步]驱动串口收发(接收不定长数据)

本文介绍了STC32G144K246单片机的串口功能配置与使用。该芯片具有8组独立USART,支持异步/同步模式,各串口可独立配置波特率并支持DMA传输。重点讲解了串口寄存器配置方法,包括引脚设置、波特率计算和中断处理。特别指出RX引脚需配置为开漏或准双向口以避免接收乱码。还介绍了通过定时器实现不定长数据接收的技术方案,并提供了完整的初始化代码和中断处理函数示例。文中包含串口时序图、寄存器配置表等实用参考信息,适合嵌入式开发者快速上手多串口应用开发。

sinat_58149788的博客 194

【并发编程】AbstractQueuedSynchronizer(AQS)JDK1.8 源码分析

AQS实现机制、AQS特性、acquire加锁流程

七夜同学的博客 690

Camera HAL 多线程管理详解

本文摘要:Camera HAL 采用双线程管理体系(CAMX与CHI-CDK)实现高效并发处理。CAMX ThreadManager负责HAL内部及框架交互,采用线程池+任务调度机制,将节点处理、回调等封装为Job异步执行;CHI ThreadManager专注于OEM定制逻辑,支持异步/同步两种作业模式。两套系统通过函数指针解耦但共享地址空间,共同实现硬件流水线的强实时性。文章详细解析了两者的类层次架构、核心数据结构及典型应用场景,并提供了问题排查的代码切入点,为Camera HAL开发与性能优化提供指导

DU_YULIN的博客 54

JDK1.8源码分析之AbstractQueuedSynchronizer

一、前言   在锁框架中,AbstractQueuedSynchronizer抽象类可以毫不夸张的说,占据着核心地位,它提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。所以很有必要好好分析。 二、AbstractQueuedSynchronizer数据结构   分析类,首先就要分析底层采用了何种数据结构,抓住核心点进行分析,经过分析可知,AbstractQueued...

逍遥飞鹤的专栏 654

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

【JUC】JDK1.8源码分析之AbstractQueuedSynchronizer

一、前言   在锁框架中,AbstractQueuedSynchronizer抽象类可以毫不夸张的说,占据着核心地位,它提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。所以很有必要好好分析。 二、AbstractQueuedSynchronizer数据结构   分析类,首先就要分析底层采用了何种数据结构,抓住核心点进行分析,经过分析可知,AbstractQueued...

weixin_33786077的博客 364

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

JDK1.8并发之CountDownLatch

CountDownLatch CountDownLatch 是java.util.concurrent包中的类,初始化时需要一个正整数参数作为初始 status 值,Thread#1 中每次调用它的countDown()方法都使得 status 减一,Thread#2 中调用它的await()方法会导致 Thread#2 阻塞直到 status 为0。 它可以用来设置一个任务阻塞直到其他 n...

哈罗德Android笔记 2274

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

JDK1.8 AbstractQueuedSynchronizer的实现分析(上)

深度解析Java 8:JDK1.8 AbstractQueuedSynchronizer的实现分析(上)   作者 刘锟洋 发布于 2014年7月31日 http://www.infoq.com/cn/articles/jdk1.8-abstractqueuedsynchronizer 前言 Java中的FutureTask作为可异步执行任务并可获取执行结果而被大家所熟知。通常可以使用

笔记 1477

深度解析Java 8:JDK1.8 AbstractQueuedSynchronizer的实现分析

https://www.jianshu.com/p/259780bb79f2

wangbaosongmsn的博客 132

AbstractQueuedSynchronizer---JDK1.8源码分析

AQS源码分析---JDK1.8一. AQS相关知识点①. AQS介绍②. AQS核心思想②. 实现方式:③. CLH--- 同步队列二. AQS源码分析①. state状态②. AQS类中的Node类③. 获取独占锁acquire()④. addWaiter(Node) 添加元素到阻塞队列中⑤. enq() 自旋操作添加元素⑥. acquireQueued() 尝试获取锁⑦. shouldParkAfterFailedAcquire() 判断失败获取后是否可以挂起当前线程⑧. parkAndCheckI

626

源码分析_源码分析JDK8之AbstractQueuedSynchronizer

前言源码分析我认为主要有两个作用:满足好奇心,我想每一个有追求的人都不会满足于仅仅做一个API Caller实现功能就好,我们也想知道它到底是怎么实现的;借鉴与升华,当我们明白了一个类的设计原理,在一定的情境下我们可以借鉴其设计哲学,甚至针对我们自己特殊的业务场景对其进行改良与优化。下面我就以这篇文章开启我的源码阅读之旅。总体而言,我会从这个类基本结构入手,然后分析原理,再看看已有的应用,并进行分...

weixin_32797081的博客 206

AbstractQueuedSynchronizer AQS源码分析

申明:jdk版本为1.8 AbstractQueuedSynchronizer是jdk中实现锁的一个抽象类,有排他和共享两种模式。 我们这里先看排他模式,共享模式后面结合java.util.concurrent.locks.ReentrantReadWriteLock单独写一篇随笔。 后面还会分析可重入锁java.util.concurrent.locks.ReentrantLock。 言...

weixin_30950887的博客 152

JDK17 AbstractQueuedSynchronizer 一 同步队列

抽象队列同步器是JDK提供的用于管理线程间同步状态的类。常见的同步器类ReentrantLock, CountDownLatch, Semaphore等都是AbstractQueuedSynchronizer的子类。AQS提供三个功能。

2301_79308687的博客 1785

【AQS】JDK1.8 源码分析 之 AbstractQueuedSynchronizer

好几年没有更新博客了,满屋子的蜘蛛网

植富宝 294

JDK源码分析-AbstractQueuedSynchronizer(1)

概述前文「JDK源码分析-Lock&Condition」简要分析了 Lock 接口,它在 JDK 中的实现类主要是 ReentrantLock (可译为“重入锁”...

WriteOnRead 457

JDK1.8 ReentrantLock相关源码

java.util.concurrent.locks.ReentrantLock内部维护了AbstractQueuedSynchronizer的实现类java.util.concurrent.locks.ReentrantLock.Sync,主要是基于AbstractQueuedSynchronizer实现的一些同步功能,其中AbstractQueuedSynchronizer内部也是基于LockSupport.park(this);

yaoct的博客 1004

JDK1.8源码学习篇一——AbstractQueuedSynchronizer学习笔记

一、引言      最近想深入学习一下java并发的基础知识,总感觉在对java.util.concurrent一知半解,很多东西好像只有点印象,这次接着学习源码的机会来深入了解一下。那么为什么把AbstractQueuedSynchronizer这个类放在最前面呢?其实相信很多人跟我有同样的经历,首先学习的是ExecuteService线程池,然后学习里面的工厂类Executors,和其中的su...

fyhailin的专栏 711
上一篇: 深度解析Java 8:AbstractQueuedSynchronizer的实现分析(下)
下一篇: Java并发---- Executor并发框架--ThreadToolExecutor类详解(execute方法,关闭方法)
weiythi
博客等级 码龄16年 23粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值