AQS结构及原理分析

如何理解AQS 这里需要结合acquireQueued()方法理解,当线程被唤醒后,会进入acquireQueued()方法中的if(p==head && tryAcquier(arg))逻辑判断,当条件成立是,被唤醒的线程会将自己所在的节点设置为head,表示已经获取到资源,此时,acquire()方法也执行完毕了。如果CAS操作设置成,则唤醒队列中的后继结点。在同步队列中,如果当前线程获取资源失败,就会通过addWaiter()方法将当前线程放入队列的尾部,并且保持自旋的状态,不判断自己所在的节点是否是队列的头结点。 阅读详情

AQS介绍

AQS,即AbstractQueuedSynchronizer, 队列同步器,它是Java并发用来构建锁和其他同步组件的基础框架。来看下同步组件对AQS的使用:

AQS是一个抽象类,主是是以继承的方式使用。AQS本身是没有实现任何同步接口的,它仅仅只是定义了同步状态的获取和释放的方法来供自定义的同步组件的使用。从图中可以看出,在java的同步组件中,AQS的子类(Sync等)一般是同步组件的静态内部类,即通过组合的方式使用。

AQS原理简介

AQS的实现依赖内部的同步队列(FIFO双向队列),如果当前线程获取同步状态失败,AQS会将该线程以及等待状态等信息构造成一个Node,将其加入同步队列的尾部,同时阻塞当前线程,当同步状态释放时,唤醒队列的头节点。

上面说的有点抽象,来具体看下,首先来看AQS最主要的三个成员变量:

    private transient volatile Node head;
    
    private transient volatile Node tail;

    private volatile int state;

上面提到的同步状态就是这个int型的变量state. head和tail分别是同步队列的头结点和尾结点。假设state=0表示同步状态可用(如果用于锁,则表示锁可用),state=1表示同步状态已被占用(锁被占用)。

下面举例说下获取和释放同步状态的过程:

获取同步状态

假设线程A要获取同步状态(这里想象成锁,方便理解),初始状态下state=0,所以线程A可以顺利获取锁,A获取锁后将state置为1。在A没有释放锁期间,线程B也来获取锁,此时因为state=1,表示锁被占用,所以将B的线程信息和等待状态等信息构成出一个Node节点对象,放入同步队列,head和tail分别指向队列的头部和尾部(此时队列中有一个空的Node节点作为头点,head指向这个空节点,空Node的后继节点是B对应的Node节点,tail指向它),同时阻塞线程B(这里的阻塞使用的是LockSupport.park()方法)。后续如果再有线程要获取锁,都会加入队列尾部并阻塞。

释放同步状态

当线程A释放锁时,即将state置为0,此时A会唤醒头节点的后继节点(所谓唤醒,其实是调用LockSupport.unpark(B)方法),即B线程从LockSupport.park()方法返回,此时B发现state已经为0,所以B线程可以顺利获取锁,B获取锁后B的Node节点随之出队。

上面只是简单介绍了AQS获取和释放的大致过程,下面结合AQS和ReentrantLock源码来具体看下JDK是如何实现的,特别要注意JDK是如何保证同步和并发操作的。

AQS源码分析

接下来以ReentrantLock的源码入手来深入理解下AQS的实现。
上面说过AQS一般是以继承的方式被使用,同步组件内部组合一个继承了AQS的子类。
在ReentrantLock类中,有一个Sync成员变量,即是继承了AQS的子类,源码如下:

 public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;

    /**
     * Base of synchronization control for this lock. Subclassed
     * into fair and nonfair versions below. Uses AQS state to
     * represent the number of holds on the lock.
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        ...
    }
}

这里的Sync也是一个抽象类,其实现类为FairSync和NonfairSync,分别对应公平锁和非公平锁。ReentrantLock的提供一个入参为boolean值的构造方法,来确定使用公平锁还是非公平锁:

     public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
     }

获取锁

这里以NonfairSync类为例,看下它的Lock()的实现:

     final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
     }

lock方法先通过CAS尝试将同步状态(AQS的state属性)从0修改为1。若直接修改成功了,则将占用锁的线程设置为当前线程。看下compareAndSetState()和setExclusiveOwnerThread()实现:

     protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
     }

可以看到compareAndSetState底层其实是调用的unsafe的CAS系列方法。

     protected final void setExclusiveOwnerThread(Thread thread) {
        exclusiveOwnerThread = thread;
    }

exclusiveOwnerThread属性是AQS从父类AbstractOwnableSynchronizer中继承的属性,用来保存当前占用同步状态的线程。

如果CAS操作未能成功,说明state已经不为0,此时继续acquire(1)操作,这个acquire()由AQS实现提供:

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

代码很短,不太好了理解,转换下写法(代码1):

    public final void acquire(int arg) {
        boolean hasAcquired = tryAcquire(arg);
        if (!hasAcquired) {
            Node currentThreadNode = addWaiter(Node.EXCLUSIVE);
            boolean interrupted = acquireQueued(currentThreadNode, arg);
            if (interrupted) {
                selfInterrupt();
            }
        }
    }

简单解释下:
tryAcquire方法尝试获取锁,如果成功就返回,如果不成功,则把当前线程和等待状态信息构适成一个Node节点,并将结点放入同步队列的尾部。然后为同步队列中的当前节点循环等待获取锁,直到成功。

首先看tryAcquire(arg)在NonfairSync中的实现(这里arg=1):

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
        
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    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);
                return true;
            }
            return false;
        }

首先获取AQS的同步状态(state),在锁中就是锁的状态,如果状态为0,则尝试设置状态为arg(这里为1), 若设置成功则表示当前线程获取锁,返回true。这个操作外部方法lock()就做过一次,这里再做只是为了再尝试一次,尽量以最简单的方式获取锁。

如果状态不为0,再判断当前线程是否是锁的owner(即当前线程在之前已经获取锁,这里又来获取),如果是owner, 则尝试将状态值增加acquires,如果这个状态值越界,抛出异常;如果没有越界,则设置后返回true。这里可以看非公平锁的涵义,即获取锁并不会严格根据争用锁的先后顺序决定。这里的实现逻辑类似synchroized关键字的偏向锁的做法,即可重入而不用进一步进行锁的竞争,也解释了ReentrantLock中Reentrant的意义。

如果状态不为0,且当前线程不是owner,则返回false。
回到上面的代码1,tryAcquire返回false,接着执行addWaiter(Node.EXCLUSIVE),这个方法创建结点并入队,来看下源码:


    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对象,Node中包含了当前线程和Node模式(这时是排他模式)。tail是AQS的中表示同步队列队尾的属性,刚开始为null,所以进行enq(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;
                    }
                }
            }
        }

方法体是一个死循环,本身没有锁,可以多个线程并发访问,假如某个线程进入方法,此时head, tail都为null, 进入if(t==null)区域,从方法名可以看出这里是用CAS的方式创建一个空的Node作为头结点,因为此时队列中只一个头结点,所以tail也指向它,第一次循环执行结束。注意这里使用CAS是防止多个线程并发执行到这儿时,只有一个线程能够执行成功,防止创建多个同步队列。

进行第二次循环时(或者是其他线程enq时),tail不为null,进入else区域。将当前线程的Node结点(简称CNode)的prev指向tail,然后使用CAS将tail指向CNode。看下这里的实现:


    private final boolean compareAndSetTail(Node expect, Node update) {
            return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
        }

expect为t, t此时指向tail,所以可以CAS成功,将tail重新指向CNode。此时t为更新前的tail的值,即指向空的头结点,t.next=node,就将头结点的后续结点指向CNode,返回头结点。经过上面的操作,头结点和CNode的关系如图:

其他线程再插入节点以此类推,都是在追加到链表尾部,并且通过CAS操作保证线程安全。

通过上面分析可知,AQS的写入是一种双向链表的插入操作,至此addWaiter分析完毕。

addWaiter返回了插入的节点,作为acquireQueued方法的入参,看下源码:

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

可以看到,acquireQueued方法也是一个死循环,直到进入 if (p == head && tryAcquire(arg))条件方法块。还是接着刚才的操作来分析。acquireQueued接收的参数是addWaiter方法的返回值,也就是刚才的CNode节点,arg=1。node.predecessor()返回CNode的前置节点,在这里也就是head节点,所以p==head成立,进而进行tryAcquire操作,即争用锁, 如果获取成功,则进入if方法体,看下接下来的操作:

1) 将CNode设置为头节点。
2) 将CNode的前置节点设置的next设置为null。

此时队列如图:

上面操作即完成了FIFO的出队操作。
从上面的分析可以看出,只有队列的第二个节点可以有机会争用锁,如果成功获取锁,则此节点晋升为头节点。对于第三个及以后的节点,if (p == head)条件不成立,首先进行shouldParkAfterFailedAcquire(p, node)操作(争用锁失败的第二个节点也如此), 来看下源码:

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

shouldParkAfterFailedAcquire方法是判断一个争用锁的线程是否应该被阻塞。它首先判断一个节点的前置节点的状态是否为Node.SIGNAL,如果是,是说明此节点已经将状态设置如果锁释放,则应当通知它,所以它可以安全的阻塞了,返回true。

如果前节点的状态大于0,即为CANCELLED状态时,则会从前节点开始逐步循环找到一个没有被“CANCELLED”节点设置为当前节点的前节点,返回false。在下次循环执行shouldParkAfterFailedAcquire时,返回true。这个操作实际是把队列中CANCELLED的节点剔除掉。

前节点状态小于0的情况是对应ReentrantLock的Condition条件等待的,这里不进行展开。

如果shouldParkAfterFailedAcquire返回了true,则会执行:“parkAndCheckInterrupt()”方法,它是通过LockSupport.park(this)将当前线程挂起到WATING状态,它需要等待一个中断、unpark方法来唤醒它,通过这样一种FIFO的机制的等待,来实现了Lock的操作。

释放锁

通过ReentrantLock的unlock方法来看下AQS的锁释放过程。来看下源码:

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

    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

unlock调用AQS的release()来完成, AQS的如果tryRelease方法由具体子类实现。tryRelease返回true,则会将head传入到unparkSuccessor(Node)方法中并返回true,否则返回false。首先来看看Sync中tryRelease(int)方法实现,如下所示:

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
    setExclusiveOwnerThread(null);
    }
    setState(c);
    return free
}

这个动作可以认为就是一个设置锁状态的操作,而且是将状态减掉传入的参数值(参数是1),如果结果状态为0,就将排它锁的Owner设置为null,以使得其它的线程有机会进行执行。
在排它锁中,加锁的时候状态会增加1(当然可以自己修改这个值),在解锁的时候减掉1,同一个锁,在可以重入后,可能会被叠加为2、3、4这些值,只有unlock()的次数与lock()的次数对应才会将Owner线程设置为空,而且也只有这种情况下才会返回true。

在方法unparkSuccessor(Node)中,就意味着真正要释放锁了,它传入的是head节点(head节点是占用锁的节点),看下源码:

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

内部首先会发生的动作是获取head节点的next节点,如果获取到的节点不为空,则直接通过:“LockSupport.unpark()”方法来释放对应的被挂起的线程,这样一来将会有一个节点唤醒后继续进入循环进一步尝试tryAcquire()方法来获取锁。

以上ReentrantLock的释放锁的过程就分析完毕了。
结合对ReentrantLock的加解锁的过程的分析,本文对AQS的内部结构及原理进行了深入的分析,应看到Java通过一个AQS队列解决了许多问题,这个是Java层面的队列模型,其实我们也可以利用许多队列模型来解决自己的问题,甚至于可以改写模型模型来满足自己的需求。

https://segmentfault.com/a/1190000008471362(想学习获取更多学习视频关注【八戒程序猿】)

Android 16(API 36)状态栏颜色适配全攻略:从沉浸式到自定义背景 本文全面解析Android 16(API 36)强制沉浸式状态栏带来的适配挑战,提供了从FrameLayout包裹法到动态修改Window背景色的核心解决方案。针对传统状态栏颜色设置失效问题,详细阐述了如何利用WindowInsets API实现自定义背景,并涵盖全屏模式、Fragment切换及第三方ROM兼容性等实战场景,为开发者提供一站式适配指南。 阅读详情

相关推荐

西门子V90 PN伺服控制核心:FB284功能块详解与实战

在工业自动化中,伺服定位控制是运动控制的基础环节,其本质是PLC通过PROFINET协议与伺服驱动器实现高速、确定性数据交互。FB284作为西门子为V90 PN定制的标准化功能块,封装了GSD映射、状态机管理与周期性PDO同步机制,将底层寄存器操作抽象为高可靠调用接口。相比MOVE指令或MC_MoveAbsolute等通用方案,FB284显著降低时序错乱风险,提升多轴同步精度与故障响应能力。它广泛应用于包装、灌装、装配等中端产线,尤其适配S7-1200/1500平台下的快速部署与现场维护。本文聚焦V90 P

weixin_42696271的博客 300

浅谈Java并发编程系列(九)—— AQS结构及原理分析

AQS介绍 AQS,即AbstractQueuedSynchronizer, 队列同步器,它是Java并发用来构建锁和其他同步组件的基础框架。来看下同步组件对AQS的使用: AQS是一个抽象类,主是是以继承的方式使用。AQS本身是没有实现任何同步接口的,它仅仅只是定义了同步状态的获取和释放的方法来供自定义的同步组件的使用。从图中可以看出,...

weixin_34273481的博客 701

ArcGIS中地理坐标系与投影坐标系以及投影转换

简单介绍arcgis软件中坐标系定义、设置和常见问题。

weixin_41399650的博客 8万+

什么是AQS及其原理

GitHub:https://github.com/JDawnF 1、AQS简介 AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.lang.concurrent)下locks包内的一个类。它实现了一个FIFO(FirstIn、FisrtOut先进先出)的队列。底层实现的数据结构是一个双向链表。 Sync queue:同步队列,是一个双向链...

striveb的博客 4万+

基于8086微机原理数字钟计时器系统设计

*单片机设计介绍,基于8086微机原理数字钟计时器系统设计。

2201_75940997的博客 1279

【功能安全】软件安全架构

目录01 软件安全架构介绍02 软件架构设计模板03 软件架构设计示例 软件架构设计的目的 软件架构设计的原则 软件架构设计输入与输出 软件架构设计的要求 注:软件架构设计和软件安全要求之间的双向可追溯性。软件架构设计原则: 软件架构静态/动态设计(参考秒尼科技术) 软件架构静态设计 软件架构动态设计 软件分层架构设计 软件架构设计安全机制错误探测的安全机制 其中:数据的范围检查指输入输出数据的范围进行检查,例如:在程序中我们可以通过数据范围来排除数据的正确性;合理性检查 例如:使用参

weixin_36460584的博客 511

深入理解AQS实现原理

一、AQS简介 1. 什么是AQS AQS全称为AbstractQueuedSynchronizer,翻译过来就是抽象队列同步器。AQS是一个用来构建锁和其他同步组件的基础框架,使用AQS可以简单且高效地构造出应用广泛的同步器,例如我们后续会讲到的ReentrantLock、Semaphore、ReentrantReadWriteLock和FutureTask等等。 2. AQS的核心思想 AQS核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态

weixin_41951205的博客 4144

【人工智能论文发表】基于医学病例文本和多模态大模型的医疗影像分割方法研究

摘要:本研究提出MMS-Former,一种基于级联多模态Transformer的文本引导医学图像分割框架。该模型创新性地将临床文本信息深度融入图像分割全过程,通过SwinUNETR提取视觉特征,ClinicalBERT编码病历文本,并在解码器的每个上采样阶段通过交叉注意力模块实现多级文本特征融合。实验表明,相比纯视觉模型,MMS-Former在Dice系数和IoU指标上分别提升3%以上,在处理边界模糊目标时表现尤为突出。模型还设计了结合Dice损失和图文对比损失的复合目标函数,确保分割精度与语义对齐。代码实

u012133341的博客 141

图文并茂,带你深入了解AQS的源码

文章目录前言CASAQS简介基础定义独占模式加锁过程tryAcquireaddWaiteracquireQueued释放锁tryRelease共享模式获取锁tryAcquireShareddoAcquireShared释放锁doAcquireSharedConditionawaitsignal总结最后 前言 如果你想深入研究Java并发的话,那么AQS一定是绕不开的一块知识点,Java并发包很多的同步工具类底层都是基于AQS来实现的,比如我们工作中经常用的Lock工具ReentrantLock、栅栏Coun

1073

【OpenClaw从入门到精通】第09篇:企业级实践——将OpenClaw接入钉钉,打造7×24小时数字员工(2026实测版)

本文聚焦OpenClaw的企业级落地实践,以“招聘数字专员”为核心场景,完整演示从钉钉接入到全流程自动化的实现路径。内容涵盖企业级部署架构设计、前置环境搭建、核心技能开发、流程串联、安全权限管控及运维监控六大模块,详解简历解析、岗位匹配、外呼集成、CRM同步、日历提醒等关键技能的构建逻辑与代码实现。借鉴中关村科金、网易智企的企业级实践经验,重点突破企业知识融合、安全权限管控、业务系统连接三大核心门槛,提供可直接参考的配置示例与操作步骤。所有技术方案均基于公开文档与实测验证,兼顾新手入门与进阶实操。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1172

基于电能质量治理的场景实例:统一电能质量调节器(UPQC)与并网逆变器集成

本文通过Simulink平台,详细演示了统一电能质量调节器(UPQC)与并网逆变器的集成系统建模与仿真过程。主要内容包括:1)系统架构设计,包含光伏并网系统、非线性负载和电压扰动源;2)UPQC主电路设计,包括串联/并联单元拓扑和控制策略实现;3)与并网逆变器的能量交互与协同控制逻辑;4)典型电能质量问题的仿真测试场景。结果表明,该集成系统能有效治理电压暂降(维持负载电压380V±2%)和电流谐波(电网THD<3%),直流母线电压稳定在800V±5V。该系统为应对复杂电能质量问题提供了"电压

xiaoheshang_123的博客 310

Java并发之AQS结构及原理分析

Java中的CAS CAS:全称为Compare And Swap,比较并交换,CAS 是现代操作系统,解决并发问题的一个重要手段。一个CAS涉及到了下面的操作: 假设内存中的原数据V,旧的预期值A,需要修改的新值B 1、比较 A 与 V 是否相等(比较) 2、如果比较相等,将 B 写入 V(交换) 3、返回操作是否成功 当多个线程对资源进行CAS操作时,只有一个线程能够成功,但是不会阻塞其他线程...

qq_43060759的博客 459

定位教程7---旋转中心标定之方法二

手算相机相对机器人关系

Quintin 6230

AQS结构及原理分析和Reentrant非公平锁

AQS介绍 AQS,即AbstractQueuedSynchronizer, 队列同步器,它是Java并发用来构建锁和其他同步组件的基础框架。来看下同步组件对AQS的使用: AQS是一个抽象类,主是是以继承的方式使用。AQS本身是没有实现任何同步接口的,它仅仅只是定义了同步状态的获取和释放的方法来供自定义的同步组件的使用。从图中可以看出,在java的同步组件中,AQS的子类(Sync等)一般是...

u012133048的博客 443

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

JAVA AQS结构及其原理分析

引言 AQS,即AbstractQueuedSynchronizer, 队列同步器,它是Java并发用来构建锁和其他同步组件的基础框架。大多数开发者可能都不会直接使用AQS,标准同步器类的集合能够满足绝大多数情况的需求,但如果能了解标准同步器类的实现方式,那么对于理解它们的工作原理是非常有帮助的。 AQS是一个抽象类,一般是同步组件的静态内部类,通过组合的方式使用。AQS本身没有实现任何同步接口的...

weixin_34126215的博客 185

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

java aqs实现原理_浅谈Java并发编程系列(九)—— AQS结构及原理分析

AQS介绍AQS,即AbstractQueuedSynchronizer, 队列同步器,它是Java并发用来构建锁和其他同步组件的基础框架。来看下同步组件对AQS的使用:AQS是一个抽象类,主是是以继承的方式使用。AQS本身是没有实现任何同步接口的,它仅仅只是定义了同步状态的获取和释放的方法来供自定义的同步组件的使用。从图中可以看出,在java的同步组件中,AQS的子类(Sync等)一般是同步组件...

weixin_39867594的博客 158

假人有限元模型

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

Java之Reentrantlock的实现及AQS的原理和应用

ReentrantLock意思为可重入锁,指的是一个线程能够对一个临界资源重复加锁。

qq_62592925的博客 1450

Java 并发掌握AQS的原理及应用

本文深入解析了Java并发编程中的AQS(AbstractQueuedSynchronizer)框架及其应用。主要内容包括: AQS是Java同步类(Lock、Semaphore等)的基础框架,提供原子状态管理、线程阻塞/唤醒和队列模型功能 以ReentrantLock为例,对比分析其与synchronized的特性差异,展示AQS在实际锁实现中的应用 详细剖析AQS的五层架构设计,从API层到底层数据结构,重点讲解独占锁的实现机制 介绍AQS核心数据结构Node,解析CLH变体队列的节点实现和状态管理 通

26857259 937

【深入AQS原理】我画了35张图就是为了让你深入 AQS

申明 本文首发自公众号:程序员cxuan,此文章为本人投稿文章。 已经和公众号作者沟通,文章投递公众号,博客平台发布可标记为原创。 此文章肝了很久,图片较多,希望大家喜欢。 另外,感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫 公众号刚开始运营,希望与您一同成长。 前言 谈到并发,我们不得不说AQS(AbstractQueuedSynchronizer),所谓的AQS即是抽象的队列式的同步器,...

一枝花算不算浪漫的专栏 4043

AQS之ReentrantLock源码分析

java.util.concurrent包中的大多数同步器实现都是围绕着共同的基础行为,比如等待队列、条件队 列、独占获取、共享获取等,而这些行为的抽象就是基于AbstractQueuedSynchronizer(简称 AQS)实现的,AQS是一个抽象同步框架,可以用来实现一个依赖状态的同步器。JDK中提供的大多数的同步器如Lock, Latch, Barrier等,都是基于AQS框架来实现的一般是通过一个内部类Sync继承 AQS将同步器所有调用都映射到Sync对应的方法阻塞等待队列共享/独占。

qq_45061342的博客 1360

JUC 基石之 AQS 原理

JUC 基石之 AQS 原理 文章目录JUC 基石之 AQS 原理一、简介,什么是 AQS二、相关基础知识1. synchronized 原理2. CLH 队列3. CAS 原理三、AQS 解析1. AQS 分层架构图2. AQS 核心思想3. AQS 数据结构4. AQS 源码分析(1) 获取锁a. 公平锁获取过程1. FairSync.lock() & acquire() 公平锁开始获取锁2. FairSync.tryAcquire() 公平锁尝试获取锁3. addWaiter() 进入等待队列

Au的博客 506

通过ReentrantLock的源码解析AQS的原理

Java中的大部分同步类(Lock、Semaphore、ReentrantLock等)都是基于AbstractQueuedSynchronizer(简称为AQS)实现的。AQS是一种提供了原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架 1 ReentrantLock 1.1 ReentrantLock特性概览 ReentrantLock意思为可重入锁,指的是一个线程能够对一个临界资源重复加锁。为了帮助大家更好地理解ReentrantLock的特性,我们先将ReentrantLock跟

琪琪的博客 918

阿里十年 “帕鲁” 手把手带你从ReentrantLock的实现看AQS的原理及应用

了解 AQS 基本原理以后,按照上面所说的 AQS 知识点,自己实现一个同步工具。@Override@Override@Override通过我们自己定义的 Lock 完成一定的同步功能。上述代码每次运行结果都会是 20000。通过简单的几行代码就能实现同步功能,这就是 AQS 的强大之处。我们日常开发中使用并发的场景太多,但是对并发内部的基本框架原理了解的人却不多。

zxyhj的博客 1783

从ReentrantLock的实现看AQS的原理及应用

前言 Java中的大部分同步类(Lock、Semaphore、ReentrantLock等)都是基于AbstractQueuedSynchronizer(简称为AQS)实现的。AQS是一种提供了原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架。本文会从应用层逐渐深入到原理层,并通过ReentrantLock的基本特性和ReentrantLock与AQS的关联,来深入解读AQS相关独占锁的知识点,同时采取问答的模式来帮助大家理解AQS。由于篇幅原因,本篇文章主要阐述AQS中独占锁的逻辑和Sy..

一个有情怀的程序猿博客 303

Java-ReentrantLock-AQS-原理-应用-美团技术团队

Java中的大部分同步类(Lock、Semaphore、ReentrantLock等)都是基于AbstractQueuedSynchronizer(简称为AQS)实现的。AQS是一种提供了原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架。本文会从应用层逐渐深入到原理层,并通过ReentrantLock的基本特性和ReentrantLock与AQS的关联,来深入解读AQS相关独占锁的知识点,同时采取问答的模式来帮助大家理解AQS。

Java程序员的知识博客 1281
上一篇: RocketMQ事务处理方案
下一篇: Gitlab CI yaml官方配置文件翻译
yi博说
博客等级 码龄11年 20粉丝 30原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值