Condition学习

Condition学习笔记 JDK版本:AdoptOpenJDK 11.0.10+9 1 基本概念 j.u.c包提供的Condition接口,可以看作是对Object的wait()、notify()、notifyAll()的的替代,与Lock配合使用,一般用于线程间的通信。 获取一个Condition 必须要通过Lock 的newCondition() 方法。该方法定义在接口Lock 下面,返回的结果是绑定到此 Lock 对象的新 Condition 对象。 一个Lock对象可以有多个Condition对象,每个Condition. 阅读详情

Condition接口是在java 1.5中才出现的,位于java.util.concurrent.locks包下。

它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition。Lock替换synchronized方法和语句的使用, Condition取代了对象监视器方法的使用。

以生产者与消费者案例举例对比两种的共同与差异:

  1. Object的wait()、notify()必须保证生产者与消费者使用的监视器对象是同一个,Lock与Condition组合需保证锁对象是同一个lock实例
  2. Object的notify()无法区分生产者或消费者,所以存在唤醒同类的情况,在多生差多消费者模式下可能出现假死(过多的同类唤醒同类),所以需要使用notifyAll。
  3. Condition可以通过使用不同的condition实例对象对生产者消费者进行分类,从而达到指定某一类休眠或唤醒。

使用对象监视器方法必须保证:

  1. Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition() ,每一个condition示例唯一对应一个lock实例,一个lock可以生产多个condition
  2. 调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用

等待队列是有序的FIFO先进先出队列,调用signal()方法是按顺序从一个头节点开始“激活”,如果失败的话才会依次继续尝试第二个,默认激活等待时间最长的也就是队列的最前端(这里激活不是真正的激活而只是将节点加入到同步阻塞队列尾部),加入到同步阻塞队列。也就是说先等待的先进入同步阻塞队列(这和传统的Object中的  wait/notify机制不太一样,notify方法是随机唤醒一个),但是真正的激活线程是由lock.unlock()去处理。


jdk源码中的演示demo:

class BoundedBuffer {
    final Lock lock = new ReentrantLock();
    final Condition notFull = lock.newCondition();
    final Condition notEmpty = lock.newCondition();

    final Object[] items = new Object[100];
    int putptr, takeptr, count;

    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length)
                notFull.await();
            items[putptr] = x;
            if (++putptr == items.length)
                putptr = 0;
            ++count;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0)
                notEmpty.await();
            Object x = items[takeptr];
            if (++takeptr == items.length)
                takeptr = 0;
            --count;
            notFull.signal();
            return x;
        } finally {
            lock.unlock();
        }
    }
}

Condition接口

await() :造成当前线程在接到信号或被中断之前一直处于等待状态。
await(long time, TimeUnit unit) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态
awaitNanos(long nanosTimeout) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。返回值表示剩余时间,如果在nanosTimesout之前唤醒,那么返回值 = nanosTimeout - 消耗时间,如果返回值 <= 0 ,则可以认定它已经超时
awaitUninterruptibly() :造成当前线程在接到信号之前一直处于等待状态。【注意:该方法对中断不敏感】。
awaitUntil(Date deadline) :造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。如果没有到指定时间就被通知,则返回true,否则表示到了指定时间,返回返回false。
signal() :唤醒等待队列中的第一个节点。该线程从等待方法返回前必须获得与Condition相关的锁。
signalAll() :唤醒所有等待线程。能够从等待方法返回的线程必须获得与Condition相关的锁。


Condition的优势

对于等待/通知机制,简化而言,就是等待一个条件,当条件不满足时,就进入等待,等条件满足时,就通知等待的线程开始执行。为了实现这种功能,需要进行wait的代码部分与需要进行通知的代码部分必须放在同一个对象监视器里面执行,才能实现多个阻塞的线程同步执行代码,等待与通知的线程也是同步进行。对于wait/notify而言,对象监视器与等待条件结合在一起 即synchronized(对象)利用该对象去调用wait以及notify。但是对于Condition类,是对象监视器与条件分开,Lock类来实现对象监视器,condition对象来负责条件,去调用await以及signal。而且一个Lock可以创建多个不同的Condition实例(也就意味着有多个等待队列,但是同步阻塞队列是唯一的),一个Condition实例可以在不同时机不同条件下执行等待唤醒操作。


Condition的实现分析

1. 属性

我们先看下ConditionObject中的属性:

    /** First node of condition queue. */
    private transient Node firstWaiter;
    /** Last node of condition queue. */
    private transient Node lastWaiter;

每个条件变量都维护了一个容器,ConditionObject中的容器就是单向链表队列,上面的属性就是队列的头结点firstWaiter和尾结点lastWaiter,需要注意,条件队列中的头结点不是虚拟头结点,而是包装了等待线程的节点!其类型和同步队列一样,也是使用AQS的内部类Node来构成,但与同步队列不同的是,条件队列是一个单向链表,所以他并没有使用Node类中的next属性来关联后继Node,而使用的nextWaiter

这里我们需要注意,nextWaiter是没用volatile修饰的,为什么呢?因为线程在调用await方法进入条件队列时,是已经拥有了锁的,此时是不存在竞争的情况,所以无需通过volatile和cas来保证线程安全。而进入同步队列的都是抢锁失败的,所以肯定是没有锁的,故要考虑线程安全

最后需要注意一点的是,条件队列里面的Node只会存在CANCELLED和CONDITION的状态

2. 等待队列

ConditionObject是AQS的内部类,它实现了Condition接口。每个Condition对象都包含一个条件队列(等待队列)。等待队列是一个FIFO(first in first out)的队列,在队列中的每个节点都包含了一个线程引用,该线程就是在Condition对象上等待的线程,如果一个线程调用了Condition.await()方法,那么该线程将会构造成节点加入等待队列并进入等待状态,然后释放锁。AQS有一个同步队列和多个等待队列,节点都是Node。等待队列的基本结构如下所示。

等待队列分为首节点和尾节点。当一个线程调用Condition.await()方法,将会以当前线程构造节点,并将节点从尾部加入等待队列。新增节点就是将尾部节点指向新增的节点。节点引用更新本来就是在获取锁以后,释放锁之前的的操作,所以不需要CAS保证。同时也是线程安全的操作。

 如果从队列(同步队列和等待队列)的角度去看await()方法,当调用await()方法时,相当于同步队列的首节点(获取锁的节点)移动到Condition的等待队列中。

成功的获取锁的线程(也就是同步队列的首节点)调用await()方法,该方法会将当前线程重新构造成节点并加入到等待队列中,然后释放同步状态,唤醒同步队列中的后继节点,然后当前线程会进入等待状态。

2. 源码分析

或者参考文章AQS的ConditionObject源码详解 - 简书

2.1 等待

public final void await() throws InterruptedException {
        //判断是否当前线程是否被中断中断则抛出中断异常
      if (Thread.interrupted())
        throw new InterruptedException();
        //加入等待队列
      Node node = addConditionWaiter();
        //释放当前线程锁
      int savedState = fullyRelease(node);
      int interruptMode = 0;
 //判断是否在同步阻塞队列,如果不在则阻塞本线程,并一直循环直到被加入阻塞队列或线程中断,跳出循环
      while (!isOnSyncQueue(node)) {
        //阻塞当前线程
        LockSupport.park(this);
        //判断是否被中断
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
          break;
      }
        //获取锁,如果获取中被中断则设置中断状态
      if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
        // 清除被激活的节点,延迟执行(参考addConditionWaiter方法)
      if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
        //如果当前线程被中断,处理中断逻辑
      if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
    }


主要分以下几步
    (1)先判断是否当前线程是否被中断中断则抛出中断异常如果未中断调用addConditionWaiter()加入等
待队列
    (2)调用fullyRelease(node)释放锁使同步阻塞队列的下个节点线程能获取锁。
    (3)调用isOnSyncQueue(node)判断是否在同步阻塞队列,这里的加入同步阻塞队列操作是在另一个线
程调用signal()后加入,如果不在同步阻塞队列会进行阻塞直到被激活。
    (4)如果被激活然后调用checkInterruptWhileWaiting(node)判断是否被中断并获取中断模式。
    (5)继续调用isOnSyncQueue(node)判断是否在同步阻塞队列。
    (6)是则调用acquireQueued(node, savedState) 获取锁,获取不到,则会阻塞。关于此方法,可参考lock学习笔记02中的源码分析。acquireQueued(node, savedState)也会返回当前线程是否被中断,如果
被中断设置中断模式。
    (7)在激活后调用unlinkCancelledWaiters()清理等待队列的已经被激活的节点。
    (8)最后判断当前线程是否被中断,如果被中断则对中断线程做处理。
private Node addConditionWaiter() {
        //获取等待队列尾部节点
      Node t = lastWaiter;
      //如果尾部状态不为CONDITION,如果已经被"激活",清理之,然后重新获取尾部节点
      if (t != null && t.waitStatus != Node.CONDITION) {
        unlinkCancelledWaiters();
        t = lastWaiter;
      }
        //创建以当前线程为基础的节点,并将节点模式设置成CONDITION
      Node node = new Node(Thread.currentThread(), Node.CONDITION);
        //如果尾节点不存在,说明队列为空,将头节点设置成当前节点
      if (t == null)
        firstWaiter = node;
        //如果尾节点存在,将此节点设置成尾节点的下个节点
      else
        t.nextWaiter = node;
        //将尾节点设置成当前节点
      lastWaiter = node;
      return node;
    }
final int fullyRelease(Node node) {
    boolean failed = true;
    try {
        //获取同步阻塞队列中当前线程节点的锁状态值
      int savedState = getState();
        //释放当前线程节点锁
      if (release(savedState)) {
        failed = false;
        return savedState;
      } else {
        throw new IllegalMonitorStateException();
      }
    } finally {
        //释放失败讲节点等待状态设置成关闭
      if (failed)
        node.waitStatus = Node.CANCELLED;
    }
  }

调用getState()先获取阻塞队列中当前线程节点的锁状态值,这个值可能大于1表示多次重入,然后调用 
release(savedState)释放所有锁,如果释放成功返回锁状态值
(这里需要先熟悉一下Node的结构,可以参考一下Node笔记)
final boolean isOnSyncQueue(Node node) {
        //判断当前节点是否是CONDITION或者前置节点是否为空如果为空直接返回false
    if (node.waitStatus == Node.CONDITION || node.prev == null)
      return false;
    //如果下个节点存在,则在同步阻塞队列中,返回true
    if (node.next != null) // If has successor, it must be on queue
      return true;
        //遍历查找当前节点是否在同步阻塞队列中
    return findNodeFromTail(node);
  }
  private boolean findNodeFromTail(Node node) {
    Node t = tail;
    for (;;) {
      if (t == node)
        return true;
      if (t == null)
        return false;
      t = t.prev;
    }
  }

此方法的功能是查找当前节点是否在同步阻塞队列中,方法先是快速判断,判断不了再进行遍历查找。

(1)第一步先判断次节点是否CONDITION状态或者前置节点是否存在,如果是表明不在队列中返回false,阻
塞队列中的状态一般是0或者SIGNAL状态,而且如果当前节点在阻塞队列中且未被激活,则前置节点一定不为空
(因为阻塞队列中的第一个节点(只有它的前置节点能为null)是一个无意义的空节点)。
(2)第二步判断节点的下个节点是否存在,如果存在则表明当前当前节点已加入到阻塞队列中。
(3)如果以上2点都没法判断,也有可能刚刚加入到同步阻塞队列中,所以调用findNodeFromTail(Node 
node)做最后的遍历查找。查找从队列尾部开始查,从尾部开始查的原因是可能刚刚加入到同步阻塞队列中,从
尾部能快速定位。
private int checkInterruptWhileWaiting(Node node) {
      return Thread.interrupted() ?
        (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
        0;
    }
 
final boolean transferAfterCancelledWait(Node node) {
    if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
      enq(node);
      return true;
    }
    while (!isOnSyncQueue(node))
      Thread.yield();
    return false;
  }

此方法在线程被激活后被调用,主要功能就是判断被激活的线程是否被中断。此方法会返回2种中断状态THROW_IE
和REINTERRUPT,THROW_IE是调用signal()前被中断返回,REINTERRUPT在调用signal()后被中断返回。 此方
法先判断是否被标记中断,是的话再调用transferAfterCancelledWait(node)取判断是那种中断状态,
transferAfterCancelledWait(node)方法分2步:

    (1)用CAS方式将节点状态从CONDITION改成0,并加入到同步阻塞队列中返回true
    (2)如果不能加入到同步阻塞队列就自旋一直等待加入

如果使用await()方法上面2步其实是没什么作用其最后一定会返回false,因为await()被激活只能调用 
signal()方法,而signal()方法肯定已经将节点加入到同步阻塞队列中。所以以上逻辑是给await(long time,
TimeUnit unit)等待超时激活方法用的。
private void unlinkCancelledWaiters() {
		//获取等待队列头节点
            Node t = firstWaiter;
            Node trail = null;
            while (t != null) {
		//获取下个节点
                Node next = t.nextWaiter;
		//如果状态不为CONDITION说明已经加入阻塞队列需要清理掉
                if (t.waitStatus != Node.CONDITION) {
                    t.nextWaiter = null;
                    if (trail == null)
                        firstWaiter = next;
                    else
			//获取下个节点
                        trail.nextWaiter = next;
                    if (next == null)
                        lastWaiter = trail;
                }
                else
                    trail = t;
                t = next;
            }
        }

此方法就是从头开始查找状态不为CONDITION的节点并清理,状态不为CONDITION节点说明此节点已经加入到阻塞队列,已经不需要维护
private void reportInterruptAfterWait(int interruptMode)
            throws InterruptedException {
		//如果是THROW_IE模式直接抛出异常
            if (interruptMode == THROW_IE)
                throw new InterruptedException();
		//如果是REINTERRUPT模式标记线程中断由上层处理中断
            else if (interruptMode == REINTERRUPT)
                selfInterrupt();
        }

2.2 唤醒

signal()方法源码如下

public final void signal() {
		//是否当前线程持有锁
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
		//通知"激活"头节点线程
            if (first != null)
                doSignal(first);
        }

先调用isHeldExclusively()判断锁是否被当前线程持有,然后检查等待队列是否为空,不为空就是可以取第一
个节点调用doSignal(first)去"激活",这里激活不是真正的激活而只是将节点加入到同步阻塞队列尾部,所以上
下文中带""的激活都是这种解释。
protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

实现就是比较下当前线程和持有锁的线程是否同一个
        private void doSignal(Node first) {
            do {
		//头指头后移一位,如果后面的节点为空,则将尾指头也指向空,说明队列为空了
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
		//清空头节点的下个节点
                first.nextWaiter = null;
		//如果"激活"失败者取下个继续,直到成功或者遍历完
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }

此方法就是取当前头节点一直去尝试"激活",直到成功或者遍历完。
final boolean transferForSignal(Node node) {
		//将CONDITION状态设置成0
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
		//加入到同步阻塞队列,这里返回值p是node的前驱节点
        Node p = enq(node);
        int ws = p.waitStatus;
		//状态异常直接激活
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }


    (1)此方法先先将CONDITION状态设置成0,因为如果是CONDITION状态加入到同步阻塞队列,激活的时候是
不识别的。
    (2)加入到同步阻塞队列的尾部。所以同步阻塞队列中前面如果有多个在排队,调用unlock()不会马上激活
此节点。
    (3)状态异常直接调用unpark激活,这边按理说如果状态异常情况下激活,await()在调用unlock()被激
活后会进行相应的异常处理,但看await()代码没有处理则是正常执行。

这个方法主要就是把节点加入到同步阻塞队列的,真正的激活则是调用unlock()去处理。同步阻塞队列中的节点如何争抢锁取决于lock(公平锁还是非公平锁)参考lock笔记

AQS的同步队列与Condition的等待队列,两个队列的作用不同,事实上,每个线程也仅仅会同时存在于以上两个队列中的一个

推荐参考文章Condition源码分析 - 哈哈呵h - 博客园

java Condition源码分析_Code-lover's Learning Notes-优快云博客_condition源码

JUC学习 - Condition 一、JUC中的Condition 1、synchronized中等待和唤醒线程示例 public class SyncWaitAndNotifyTest { static Object lock = new Object(); public static class T1 extends Thread { @Override public void run() { System.out.println(System.curre 阅读详情

相关推荐

11-4 AEB 算法原理及系统组成

本专题旨在探讨如何利用仿真软件开发自动紧急制动系统AEB,主要通过整理开发流程,实现从需求到验证的全流程掌握,为后续开发提供支持;同时,研究了如何在汽车自动驾驶仿真工具中开发自己的算法,并解决了从ISO、E-CNAP、GB/T以及交通法规等提炼出功能需求的问题,以快速实现原型模型的开发。本专题重点讲解了AEB的工作原理、系统/软件架构和需求、算法模型及实现、CCRs/CCRb/CCRm建模与仿真、VRU-AEB-B/P/M建模与仿真,同时还提供了测试用例,期待将AEB算法成功地产品化。

AIgraphX 8557

java condition_多线程之Condition的简介及原理解析

上篇博文,我们重点介绍阻塞队列BlockingQueue,并实现了生产者和消费者模式。这篇博文,我们重点介绍Condition的相关内容,我们会通过两篇博文来介绍Condition。这篇是对Condition的简介,与Object类的等待通知模式简单对比,Condition接口具体实现,以及等待队列原理解析。然后通过源码解读,看具体实现并使用Condition实现生产者和消费者模式。Conditi...

weixin_39631344的博客 294

告别“为了写而写”:GJB438C-2021新规下,软件文档如何真正为项目服务?

本文深入解析GJB438C-2021新规如何重构软件文档的实战价值,通过文档体系瘦身、流程再造和敏捷化实践,显著提升军工软件项目的效率。新标准删除30%冗余文档,引入动态编制法和轻量化模板,使文档编制工作量降低37%,关键路径周期缩短15%。

weixin_30765577的博客 448

java多线程解说【陆】_锁实现:Condition的实现

上篇文章:java多线程解说【伍】_锁实现:ReentrantLock的实现 上文中我们分析了ReentrantLock的底层如何通过AQS来实现锁的申请和释放的,以及公平锁、非公平锁的区别。那么在ReentrantLock的锁机制中,还支持一种基于条件锁的实现,这就是Condition。那么这个Condition的底层是如何实现的呢,下面我们尝试进行分析。 Conditi

xinzun的专栏 736

AutoDock Vina实战:从零开始完成分子对接(附7VU6案例详解)

本文提供了一份详细的AutoDock Vina分子对接实战指南,以SARS-CoV-2 3CL蛋白酶(PDB ID: 7VU6)为例,从零开始手把手教学。内容涵盖软件安装、环境配置、受体与配体文件准备、对接参数设置,以及结果分析与可视化解读,旨在帮助计算生物学与药物发现领域的新手快速掌握这一核心技能。

ooo22的博客 537

如何点亮一颗sensor

要点亮一个sensor需要从,时钟、sensorI2C,供电,reset脚,mipi的配置几个方面一一确认。 reset脚拉高 给sensor的时钟有没有。(目前用到的常为24MHZ) 供电 查看sensor的数据手册,看有几个电源,用示波器量一下是否为手册规定的电压 比如:DVDD 数字电压: AVDD模拟电压 DOVDD芯片引脚出来的电压等为多少。 sensor的I2C能否抓到 将I2C的口对应上,用示波器量取i2c的波形。 检查有应答并且数据正确。读写地址是否正...

weixin_40787463的博客 3652

深入理解Condition实现原理

在AQS中存在两个FIFO队列:同步队列 和 等待队列。本篇文章主要是讲condition实现原理(即等待队里),同步队列实现原理看这篇文章:深入理解AQS实现原理和源码分析。等待队列是由Condition内部实现的,是一个虚拟的FIFO单向队列,在AQS中同步队列、...

qq_33996921的博客 5165

无人自行车平衡控制:最小二乘法动态零点拟合实践

本文探讨了无人自行车平衡控制中动态零点的重要性及实现方法。通过最小二乘法拟合车头角度与ROL值的线性关系,解决了固定零点在转向时导致的稳定性问题。实践表明,动态零点拟合能显著提升系统平衡稳定性并降低能耗。

uran的专栏 661

Condition解析

先看完AQShttps://blog.youkuaiyun.com/zgsxhdzxl/article/details/95032337,再来看比较容易理解。 condition可以对线程进行阻塞和唤醒。类似wait/notify,不同的是condition可以方便地对持有锁的线程进行阻塞和唤醒。 我们知道AQS中有一个队列是同步队列,condition也有一个队列叫等待队列,不过同步队列是双向的,等待队...

zgsxhdzxl的博客 253

82、yolov11检测模型迁移瑞芯微rk3588和使用昇腾设备300i DUO卡推理 batch=1/3,支持昇腾NMS迁移npu推理

本文介绍了使用昇腾设备进行分割推理的测试流程,包括两种测试方式(cann+onnx和om)。首先验证300iDUO卡的可用性,随后创建Docker镜像和容器以搭建独立环境。通过从指定仓库拉取Ubuntu 20.04镜像,创建容器并映射目录。进入容器后安装必要组件(Python3、GCC等)和系统工具(pciutils、net-tools等),为后续模型转换和迁移做准备。整个流程旨在构建可交付给第三方的标准化测试环境。

sxj731533730 1214

TMF8801 ToF激光测距传感器原理图设计,已量产(距离传感器)

这张 TMF8801 小板的外围结构就很有代表性。核心传感器是 U1 TMF8801,但真正构成量产价值的是外围那一圈:U2 把 VCC 整理成 3V,R1/R2/R5 与 R3/R4/R6 两组 10K 电阻稳定默认态,Q2 2N7002 和 U3 SN74LVC2G07DCKR 处理控制链路,传感器边上还有 C1/C4/C5 三颗 100nF 紧贴去耦。

不脱发的程序猿 162

NSBlog

http://www.mikeash.com/pyblog/ NSBlog "A failure in the hot air department" RSS feed (full text feed) accessors(2) advertisement(6) advice(4) apple(5) apress arc(5) assembly(7) a

呆萌院长 4057

uniapp(安卓苹果APP端):解决video组件播放视频卡顿,视频一直加载非常缓慢或加载不出来解决方案,解决多个video组件视频播放很卡一直加载非常慢怎么办(无论真机调试还是本地测试都完美搞定)

uni-app APP端video组件播放视频卡顿,uniapp video app 加载不出来解决方案,uniapp app使用video视频播放卡顿,uni-app APP端video组件播放视频卡顿_uniapp video老是加载,uniapp开发app视频在真机上卡顿,安卓app播放视频很卡,苹果ios真机运行播放视频加载很慢怎么办,解决UniApp中MP4视频播放卡顿问题,解决m3u8视频播放很卡的问题,uniapp 使用video组件,部分视频加载非常慢,uniapp视频播放卡顿,安卓视频播放

✅ 精选推荐文章 7919

muduoku 学习篇- condition类学习

在上一篇博客学习了muduo库对线程的封装,并且留了一个小尾巴,在muduo的线程类里面有一个成员变量是CountDownLatch类型,打开这个类可以看到这个类主要是对条件变量的封装。所以先学习muduo库对条件变量的封装。 conditon.h #ifndef MUDUO_BASE_CONDITION_H #define MUDUO_BASE_CONDITION_H #include "mud...

len_yue_mo_fu的博客 374

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

前端学习(2756):condition模拟启动配置

歌谣的博客 419

深度学习工具包 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")

Condition源码学习

总体Condition产生的图 signal() 唤醒队列是从condition阻塞队列取第一个 ,不过是放进AQS队列的队尾, 并且入队后会判断是否需要挂起 condition队列node 进入AQS队列后 会判断上一个节点是否为head节点 然后尝试加锁 否则依然会挂起 condition队列的node状态是CONDITION=-2 await是会阻塞当前线程并且会完全释放锁,然后唤醒AQS头结点来获取锁。也就是阻塞在lock外面的线程。 condition队列存储的就是曾经获取到锁,但是awai

yakax的博客 215

【java并发】java Condition学习

参考:Java并发之Condition 简介 Condition是基于Lock类存在的,也是用于线程的通信,但是是更加细粒度的 Condition的优势是支持多路等待,就是我可以定义多个Condition,每个condition控制线程的一条执行通路。传统方式只能是一路等待。 之后可以使用condition的await()和signal()方法进行线程的通信 使用案例 package lockTest.condition; import java.util.concurrent.locks.Conditi

Think_and_work的博客 215

Condition 源码学习

Condition 解析

wsdfym的博客 289

java condition 例子_java condition学习

Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition1的await()、signal()这种方式实现线程间协作更加安全和高效。为啥更安全和高效呢?简单说,他的作用是使得某些线程一起等待某个条件(Condition),只有当该条件具备(signal ...

weixin_39731271的博客 208

Spring Condition学习

Condition 是 Spring 中的一个接口,它提供了一种在 Spring 配置中基于特定条件来决定是否注册一个 bean 或者一个配置类的机制。这种机制非常灵活,允许开发者基于环境变量、系统属性、类路径资源等多种条件来动态地包含或排除配置。需要注意的是:Spring Boot 提供了许多内置的条件注解(如 @ConditionalOnProperty、@ConditionalOnClass 等),这些注解覆盖了大多数常见的使用场景,因此在可能的情况下,应优先考虑使用它们。

qq_45149567的博客 867

Condition 学习案例

import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class ConditionMain { public static void main(String[] args) { ReentrantLock lock = new ReentrantLock(); Condition condition =lock.ne.

yaobo2816的专栏 149

ant中condition学习

isfalse value="false" 断言假值假   istrue value="true"  断言真值真  结果为真                    isfalse value="true"  断言假值真   istrue value="false" 断言真值假  结果为假                  isset 检测属性是否存在 存在为真                

ld2007081055的专栏 674

java Condition 学习

java Condition

LVM23的博客 192

AQS-Condition源码学习

Condition 在使用synchronized加锁时,当线程调用wait方法后,会将线程放入等待队列中,其他线程调用notify(或notifyAll)方法后才会将当前线程唤醒,进入同步队列,而notifyAll是将等待队列中的所有线程都放入同步队列中,notify是挑选其中一个线程进入同步队列 这种原始的通知方法不能够指定通知某个线程,为了达到精准通知,因此JDK5后引入了AQS,而AQS中包含一个ConditionObject的内部类(我们经常说的Condition) Condition是由

qq_42641075的博客 183

JUC.Condition学习笔记

目录 Condition的概念 大体实现流程   I.初始化状态   II.await()*作   III.signal()*作 3个主要方法   Condition的数据结构   线程何时阻塞和释放   await()方法   signal()和signalAll()方法 Condition示例:生产者和消费者 JUC提供了Lock可以方便

novelly的专栏 1113
上一篇: AQS之Node学习
下一篇: java中断机制
MrMoving
博客等级 码龄10年 54粉丝 145原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值