什么是Java多线程的 等待(wait)/通知(notify)模式?

多线程编程中的“等待和通知机制”:wait 和 notify 方法 介绍了由 wait 和 notify 方法组成的等待和通知机制。 阅读详情

前言

最近在看一些JUC下的源码,更加意识到想要学好Java多线程,基础是关键,比如想要学好ReentranLock源码,就得掌握好AQS源码,而AQS源码中又有很多Java多线程经典的一些应用;再比如看了线程池的核心源码实现,又学到了很多核心实现,其实这些都可以提出来慢慢消化并变成自己的知识点,今天这个Java等待/通知模式其实是Thread.join()实现的关键,还有线程池工作线程中线程跟线程之间的通信的核心所在,故在此为了加深理解,做此记录!

一、什么是Java线程的等待/通知模式

1.1 等待/通知模式概述

首先先介绍下官方的一个正式的介绍:

等待/通知机制,是指一个线程A调用了对象object的wait()方法进入等待状态,而另一个线程B调用了对象object的notify或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而还行后续操作。

而我的理解是(举例说明):

假设工厂里有两条流水线,某个工作流程需要这两个流水线配合完成,这两个流水线分别是A和B,其中A负责准备各种配件,B负责租装配件之后产出输出到工作台。B的工作需要A的配件准备充分,否则就会一直等待A准备好配件,并且A准备好配件后会通过一个开头通知告诉B我已经准备好了,你那边不用一直等待了,可以继续执行任务了。流程A与流程B就是对应的线程A与线程B之间的通信,即可以理解为相互配合,具体也就是“”通知/等待“”机制!

1.2 需要注意的细节

那么,我们都知道超类Object有wait()方法与notify()/notifyAll()方法,在进行正式代码举例之前,应该先加深下对这三个方法的理解与一些细节(有一些细节确实容易被忽略)

  • 调用wait()方法,会释放锁(这一点我想大部分人都知道),线程状态由RUNNING->WAITNG,当前线程进入对象等待队列中;

  • 调用notify()/notifyAll()方法不会立马释放锁(这一点我大家人也应该知道,但是什么时候释放锁呢?--------请看下一条),notify()方法是将等待队列中的线程移到同步队列中,而notifyAll()则是全部移到同步队列中,被移出的线程状态WAITING-->BLOCKED;

  • 当前调用notify()/notifyAll()的线程释放锁了才算释放锁,才有机会唤醒wait线程返回(为什么有才有机会返回呢?------继续看下一条)

  • 从wait()返回的前提是必须获得调用对象锁,也就是说notify()与notifyAll()释放锁之后,wait()进入BLOCKED状态,如果其他线程有竞争当前锁的话,wait线程继续争取锁资格(不好理解的话,请看下面的代码举例)

  • 使用wait()、notify()、notifyAll()方法时需要先调对象加锁(这可能是最容易忽视的点了,至于为什么,请先看了代码之后,看本篇博文最后补充:wait()、notify()、notifyAll()加锁的原因----防止线程即饥饿)

二、代码举例

2.1 结合代码理解

结合上述的“工厂流程装配配件并产出的例子”,我们有两个线程(流水线)WaitThread与NotifyThread、其中WaitThread是被通知的任务,完成主要的工作(组装配件完成产品),需要时刻判断标志位(开关);NotifyThread是需要通知的任务,需要对WaitThread进行“监督通知”,两个配合才能更好完成产品的组装并输出。


public class WaitNotify {

    static Object lock = new Object();
    static boolean flag = false;
    public static void main(String[] args) {
        new Thread(new WaitThread(), "WaitThread").start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(new NotifyThread(), "NotifyThread").start();

    }

    /**
     * 流水线A,完成主要任务
     */
    static class WaitThread implements Runnable{
        @Override
        public void run() {
            // 获取object对象锁
            synchronized (lock){
                // 条件不满足时一直在等,等另外的线程改变该条件,并通知该wait线程
                while (!flag){
                    try {
                        System.out.println(Thread.currentThread() + " is waiting, flag is "+flag);
                        // wait()方法调用就会释放锁,当前线程进入等待队列。
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // TODO 条件已经满足,不继续while,完成任务
                System.out.println(Thread.currentThread() + " is running, flag is "+flag);
            }
        }
    }
    /**
     * 流水线B,对开关进行控制,并通知流水线A
     */
    static class NotifyThread implements Runnable{
        @Override
        public void run() {
            // 获取等wait线程同一个object对象锁
            synchronized (lock){
                flag = true;
                // 通知wait线程,我已经改变了条件,你可以继续返回执行了(返回之后继续判断while)
                // 但是此时通知notify()操作并立即不会释放锁,而是要等当前线程释放锁
                // TODO 我准备好配件了,我需要通知全部的组装流水线A.....
                lock.notifyAll();
                System.out.println(Thread.currentThread() + " hold lock, notify waitThread and flag is "+flag);
            }
        }
    }
}

运行main函数,输出:


Thread[WaitThread,5,main] is waiting, flag is false
Thread[NotifyThread,5,main] hold lock, notify waitThread and flag is true
Thread[WaitThread,5,main] is running, flag is true

车床流水工作开启,流水线的开关一开始是关闭的(flag=false),流水线B(NotifyThread)去开启后,开始自动唤醒流水线A(WaitThread),整个流水线开始工作了......

  • Thread[WaitThread,5,main] is waiting, flag is false: 一开始流水线A发现自己没有配件可组装,所以等流水线A准备好配件(这样是不是觉得特别傻,哈哈哈,真正的流水线不会浪费时间等的,而且会有很多条流水线B准备配件的,这里只是举例说明,望理解!);

  • Thread[NotifyThread,5,main] hold lock, notify waitThread and flag is true:流水线B准备好了配件,开启开关(flag=ture),并通知流水线A,让流水线A开始工作;

  • Thread[WaitThread,5,main] is running, flag is true,流水线B收到了通知,再次检查开关是否开启了,开启的话就开始返回继续完成工作了。

其实结合上述我举的例子还是很好理解的,下面是大概的一个粗略时序图:

image.png

 

2.2 扩展理解----wait()返回的前提是获得了锁

上述已经表达了这个注意的细节:从wait()返回的前提是必须获得调用对象锁,我们再增加能竞争lock的同步代码块(红字部分)。

public class WaitNotify {

    static Object lock = new Object();
    static boolean flag = false;
    public static void main(String[] args) {
        new Thread(new WaitThread(), "WaitThread").start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(new NotifyThread(), "NotifyThread").start();
    }

    /**
     * 流水线A,完成主要任务
     */
    static class WaitThread implements Runnable{
        @Override
        public void run() {
            // 获取object对象锁
            synchronized (lock){
                // 条件不满足时一直在等,等另外的线程改变该条件,并通知该wait线程
                while (!flag){
                    try {
                        System.out.println(Thread.currentThread() + " is waiting, flag is "+flag);
                        // wait()方法调用就会释放锁,当前线程进入等待队列。
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // TODO 条件已经满足,不继续while,完成任务
                System.out.println(Thread.currentThread() + " is running, flag is "+flag);
            }
        }
    }
    /**
     * 流水线B,对开关进行控制,并通知流水线A
     */
    static class NotifyThread implements Runnable{
        @Override
        public void run() {
            // 获取等wait线程同一个object对象锁
            synchronized (lock){
                flag = true;
                // 通知wait线程,我已经改变了条件,你可以继续返回执行了(返回之后继续判断while)
                // 但是此时通知notify()操作并立即不会释放锁,而是要等当前线程释放锁
                // TODO 我准备好配件了,我需要通知全部的组装流水线A.....
                lock.notifyAll();
                System.out.println(Thread.currentThread() + " hold lock, notify waitThread and flag is "+flag);
            }
            // 模拟跟流水线B竞争
            synchronized (lock){
                System.out.println(Thread.currentThread() + " hold lock again");
            }
        }
    }
}

输出结果:


Thread[WaitThread,5,main] is waiting, flag is false
Thread[NotifyThread,5,main] hold lock, notify waitThread and flag is true
Thread[NotifyThread,5,main] hold lock again
Thread[WaitThread,5,main] is running, flag is true

其中第三条跟第四条顺序可能会反着来的,这就是因为lock锁可能被红字部分的synchronized代码块竞争获取(这样wait()方法可能获取不到lock锁,不会返回),也可能被waitThread获取从wait()方法返回。


Thread[WaitThread,5,main] is waiting, flag is false
Thread[NotifyThread,5,main] hold lock, notify waitThread and flag is true
Thread[WaitThread,5,main] is running, flag is true
Thread[NotifyThread,5,main] hold lock again

三、等待/通知模式的应用

3.1 Thread.join()中源码应用

Thread.join()作用:当线程A等待thread线程终止之后才从thread.join()返回, 每个线程终止的前提是前驱线程终止,每个线程等待前驱线程终止后,才从join方法返回,这里涉及了等待/通知机制(等待前驱线程结束,接收前驱线程结束通知)。

Thread.join()源码中,使用while选好判断前驱线程是否活着,如果前驱线程还活着就一直wait等待,当然如果超时的话就直接返回。

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        // 这里的while(){wait(millis)} 就是利用等待/通知中的等待模式,只不过加上了超时设置
        if (millis == 0) {
            // while循环,当线程还活着的时候就一直循环等待,直到线程终止
            while (isAlive()) {
                // wait等待
                wait(0);
            }
            // 条件满足时返回
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

3.2 其它的应用

线程池的本质是使用一个线程安全的工作队列连接工作者线程和客户端线程,客户端线程将任务放入工作队列后便返回,而工作者线程则不断地从工作队列中取出工作并执行。那么,在这里的等待/通知模式的应用就是:

工作队列中线程job没有的话也就是工作队列为空的情况下,等待客户端放入工作队列线程任务,并通知工作线程继续从工作队列中获取线程执行。

注:关于线程池的应用源码这里不做介绍,因为一时也讲不完(自己也还没有完全消化),先简单介绍下应用到的地方还有概念。

补充:其实数据库的连接池也类似线程池这种工作流程,也会涉及等待/通知模式。

3.3 等待/通知范式

介绍了那么多应用,这种模式应该有个统一的范式来套用。对的,必然是有的:

对于等待者(也可以称之为消费者):


synchronized (对象lock) {
        while (条件不满足) {
            对象.wait();
        }
        // TODO 处理逻辑
    }

对于通知者(也可以称之为生产者):


synchronized (对象lock) {
        while (条件满足) {
            改变条件
            对象.notify();
        }
    }

注意:实际开发中最好采用的是超时等待/通知模式,在thread.join()源码方法中完美体现

四、wait()、notify()、notifyAll()使用前需要加锁的原因----防止线程即饥饿

(1)其实根据wait()注意事项也能明白,wait()是释放锁的,那么不加锁哪来释放锁!

(2)wait()与notify()或者notifyAll()必须是搭配一起使用的,否则线程调用object.wait()之后,没有超时机制,也没有调用notify()或者notifyAll()唤醒的话,就一直处于WAITING状态,造成调用wait()的线程一直都是饥饿状态。

(3)由于第2条的,我们已知:即便我们使用了notify()或者notifyAll()去唤醒线程,但是没有在适当的时机唤醒(比如调用wait()之前就唤醒了),那么仍然调用wait()线程处于WAITING状态,所以我们必须保证wait()方法要么不执行,要么就执行完在被唤醒。也就是下列代码中1哪里不能允许插入调用notify/notifyAll,自然而然就增加synchronized关键字,保证wait()操作整体执行不被破坏!


synchronized (对象lock) {
        while (条件不满足) {
            // 1 这里如果先执行了notify/notifyAll方法,那么2执行之后,该线程就一直WAITING
            对象.wait(); // 2
        }
        // TODO 处理逻辑
    }

用图片展示执行顺序就是:

image.png

 

(4)注意synchronized代码块中,代码错误或者其它原因线程终止的话,没有执行到wait()方法的话,是会自动释放锁的,不必担心会死锁。

这里介绍的等待/通知模式实际上就是Object的监视器方法(wait()、notify()等方法)配合Synchronized实现,而除此之外还有:

  • Condition配合Lock实现的等待/通知模式

  • LockSupport阻塞park与唤醒unpark方式(AQS源码中用到的多)

JavaEE初阶——多线程(等待-通知机制:wait-notify) —能够从应用层面上,干预到多个不同线程代码的执行顺序。相当于是在应用程序代码中,让后执行的线程,主动放弃被调度的机会,就可以让先执行的线程,先把对应的代码执行完了。【用途】——场景:【线程饿死/线程饥饿】拿到锁的线程,由于条件不足,无法执行后边的代码,释放锁之后,也参与锁竞争。此时,完全有可能导致,该线程反复获取锁,但是又无法完成实质性的逻辑。其他线程又无法拿到锁。这个情况,就称为:线程饿死/线程饥饿——可能性:【概率】这种情况出现的概率还是挺高的。 阅读详情

相关推荐

Java实现程序等待一段时间

以上就是几种常见的在Java中实现程序等待一段时间的方法。无论是使用Thread.sleep()方法、TimeUnit类,还是ScheduledExecutorService类,都可以根据自己的需求选择合适的方法来实现程序的延迟执行。在上面的代码中,通过创建ScheduledExecutorService对象并调用schedule()方法,我们可以安排一个任务在指定的时间后执行。在上面的代码中,程序会先打印"程序开始执行",然后调用Thread.sleep(5000)方法,使程序暂停执行5秒。

CyberBladeX的博客 1274

Java Thread.wait和Thread.notify方法

1. wait和notify方法 wait方法可以使当前执行代码的线程进行等待,notify方法用来通知哪些等待该对象锁的其它线程。wait和notify方法必须要获得该对象的锁,才能运行,否则会报IllegalMonitorStateException的异常。 try { Object lock = new Object(); synchronized (lock) { ...

假装你是大灰狼的专栏 3113

单片机入门说明书:从本质到架构,一文看透MCU核心原理

其实你每天用的洗衣机、刷的智能门锁、开的汽车里,都藏着它的身影。相当于工厂里的“运输轨道”,CPU算出的结果通过总线送到RAM存储,ROM里的程序通过总线传给CPU执行,外设的信号通过总线交给CPU处理,整个过程每秒能重复上百万次,确保各模块协同高效。高端单片机(比如STM32F4系列)还会配备DMA(直接存储器访问)单元,相当于“专用传送带”——不需要CPU干预,就能直接让外设和RAM之间传输数据(比如让ADC采集的温度数据直接存进RAM),大大降低CPU负担,让CPU能专注处理更重要的任务。

IAMIF12的博客 1041

java线程 wait notify_Java多线程中的wait/notify通信模式

前言最近在看一些JUC下的源码,更加意识到想要学好Java多线程,基础是关键,比如想要学好ReentranLock源码,就得掌握好AQS源码,而AQS源码中又有很多Java多线程经典的一些应用;再比如看了线程池的核心源码实现,又学到了很多核心实现,其实这些都可以提出来慢慢消化并变成自己的知识点,今天这个Java等待/通知模式其实是Thread.join()实现的关键,还有线程池工作线程中线程跟线程...

weixin_29096377的博客 378

Python深度学习基于Tensorflow(17)基于Transformer的图像处理实例VIT和Swin-T

定义窗口注意力机制,与普通的注意力机制不同,其是在各个窗口中执行注意力机制。从中可以看到,其创新点主要是将图片进行拆分作为序列数据带入。差不多,主要实现的是一个下采样的算法过程;相同位置的像素绑定到一起构成一张新的。模型定义完毕后,初始化模型并开始训练。由于层之间重复性出现,可以定义一个。中,这里先实现拆分图片类。进行操作时我们定义三个类。定义一个多头注意力机制类。的数据,导入数据如下。导入数据,这里同样用。

bigcrab的博客 1634

从冰棍到铸钢:手把手用Fluent融化凝固模型模拟3个不同场景(含案例设置对比)

本文深入探讨了Fluent融化凝固模型在冰棍融化、巧克力涂层凝固和钢铁连铸三个不同场景中的应用。通过详细的参数设置和案例对比,帮助工程师掌握相变模拟的核心技巧,提升工业级CFD分析的精度和效率。

weixin_42522953的博客 471

【Java】三种等待机制

【AT】三种等待机制一、 等待机制种类二、 三种等待机制应用场景三、显示等待介绍3.1 相关概念3.2 显示等待用到的两个类3.2.1 WebDriverWait3.2.2 ExpectedConditions3.2.3 显示等待实例3.3 显示等待机制 一、 等待机制种类 强制等待:sleep(不推荐) 全局隐式等待(在服务端等待) driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 显式等待(在客户端等待)

长期关注AI发展路径、技术价值转化与系统性落地。 4173

银河麒麟服务器(ky10 server)arm、x86安装qemu虚拟机

接下来就可以新建服务器了。

zengliguang的专栏 8711

Java多线程中的 wait() 和 notify() 方法

多线程并发的场景下,有时需要某些线程先执行,这些线程执行结束后其他线程再继续执行, wait()和notify()是Object类的方法,用于线程的等待与唤醒,必须搭配synchronized 锁来使用。

sinat_31583645的博客 4351

从像素到光影:解析《黑神话:悟空》中Nanite与Lumen的协同渲染革命

本文深度解析了《黑神话:悟空》如何利用Unreal Engine 5的Nanite与Lumen技术实现渲染革命。Nanite处理亿级多边形几何细节,无需传统LOD优化;Lumen提供全动态全局光照,实现实时光线反弹。两者协同工作,为游戏带来电影级视觉体验,重塑了实时渲染的技术标准与工作流程。

f6g7h8i9j的博客 425

EDEM在农业机械设计中的实战应用:以谷物收割机优化为例

本文以谷物收割机优化为例,详细阐述了EDEM离散元仿真软件在农业机械设计中的实战应用。通过构建精准的“数字谷物”模型与农机部件动态界面,利用GPU加速完成大规模颗粒系统仿真,有效诊断并解决了籽粒夹带损失与清选负荷不均等田间难题,实现了从仿真分析到田间验证的设计优化闭环。

weixin_29256771的博客 108

面试官:什么是Java多线程的 等待(wait)/通知(notify)模式?

最近在看一些JUC下的源码,更加意识到想要学好Java多线程,基础是关键,比如想要学好ReentranLock源码,就得掌握好AQS源码,而AQS源码中又有很多Java多线程经典的一些应用;再比如看了线程池的核心源码实现,又学到了很多核心实现,其实这些都可以提出来慢慢消化并变成自己的知识点,今天这个Java等待/通知模式其实是Thread.join()实现的关键,还有线程池工作线程中线程跟线程之间的通信的核心所在,故在此为了加深理解,做此记录!...

mf97532的博客 655

SAP 销售订单BOM使用场景简介

通常在MTO的生产场景中,我们会根据已创建的SO去展开BOM去驱动生产,如果我们生产地产品BOM是通用性的通常我们用标准BOM的方式就可以实现,但是实际在生产过程中往往不会这样,不同的客户对某些物料的规格就不相同,就会涉及产生不同的BOM,但是该客户的产品又不存在通用性,这个时候就会引入概念就是销售订单BOM,先有销售订单然后根据销售订单+行项目创建BOM。销售BOM:根据销售订单号+行项目号创建的BOM,是根据特定的销售订单或者可以理解为特定的客户创建的BOM。

我小时候很黑的博客 4220

彻底搞懂Java的等待-通知(wait-notify)机制

线程的生命周期转换 新建状态(New):新建一个线程对象。 就绪/可运行状态(Runnable):线程对象创建后,其他线程调用了该对象的start方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。 运行状态(Running):就绪状态的线程获得CPU并执行程序代码。 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用...

全菜工程师小辉的博客 1万+

OpenClaw与传统AI助手区别,为什么要本地部署

OpenClaw是一款本地部署的开源AI助手框架,与ChatGPT等云端服务相比具有显著优势。它支持完全离线运行,数据隐私性高,所有信息都存储在本地设备上,避免了云端服务的隐私风险。OpenClaw采用模块化设计,可自由定制功能,且无需支付订阅费用,只需一次性硬件投入。推荐在树莓派、迷你主机等设备上部署,最低配置仅需1核CPU和1GB内存。安装过程包含系统初始化、依赖安装、配置设置等步骤,支持通过systemd服务实现开机自启和后台运行。特别适合注重数据安全、需要离线使用或预算有限的用户群体。

一键难忘的博客 1690

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Java多线程wait()和notify()方法图解

多线程场景下 wait 和notify 方法详解,注意事项,内部阻塞队列和等待队列的过程,wait和sleep方法的区别

VIBE的博客 4249

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

【多线程初阶】wait 和 notify(线程的等待通知机制)

本节⽬标• 掌握 wait 和 notify(线程的等待通知机制)

2402_85428625的博客 2981

老版QQ原生表情gif动态

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

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java等待唤醒机制wait/notify深入解析

本文将帮助你彻底弄明白Java的wait/notify等待唤醒机制。为了弄明白wait/notify机制,我们需要清楚线程通信、volatile和synchronized关键字、wait/notify方法、Object的monitor机制。本文将会从这几个方面详细讲解Java的wait/notify等待唤醒机制。 一、线程通信 如果一个线程从头到尾执行完也不和别的线程打交道的话,那就不会有各种安全性问题了。但是协作越来越成为社会发展的大势,一个大任务拆成若干个小任务之后...

1万+

多线程-线程的等待通知wait、notify

线程的等待通知是多线程编程中常用的一种机制,用于线程之间的协作和同步。在Java中,线程的等待通知通过使用wait()notify()和方法来实现。由于线程之间是抢占式执⾏的, 因此线程之间执⾏的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执⾏先后顺序,所以我们需要wait()、notify()来实现这些功能。2.wiat()方法2.1 wait 做的事情:•使当前执⾏代码的线程进⾏等待. (把线程放到等待队列中)•释放当前的锁•。

weixin_71841320的博客 1798

Java 线程等待通知机制(wait、notify)

专栏原创出处:github-源笔记文件 ,github-源码 ,欢迎 Star,转载请附上原文出处链接和本声明。 什么是等待/通知机制 假设有两个线程,一个生产数据,一个消费数据。如何保证生产线程生产出数据后通知给消费线程,消费线程在没有数据可被消费情况下等待有数据呢? 一般的做法是采用轮询方法,一直 while 循环(中间睡眠几豪秒)判断是否有数据。该办法可能存在的问题是 难以确保及时性...

2.wa 2002

【Java多线程】wait方法和notify方法

介绍wait方法和notify方法

chaodddddd的博客 1427

【Java多线程编程】wait与notify方法详解

本期讲解:Java 多线程中的 wait方法、notify方法、notifyAll方法,wait方法与sleep方法之间的区别。

我的主页 4496

多线程之间进行通信wait(等待)/notify(通知)

想要后执行的逻辑等待先执行的逻辑先跑,跑完后再继续执行。我们虽然无法直接干预调度器的顺序,但是可以让后执行的逻辑等待,等待到先执行的逻辑跑完了,通知当前线程,让他继续执行。方法:1.join()方法:join是等另一个线程彻底执行完,才继续执行。2.wait()方法:wait也是等,是等到另一个线程执行到notify后,才继续执行(不需要另一个线程执行完)

2301_80235470的博客 998

wait 和 notify

wait 和 notify 简介以及使用方式,举例内部实现,以及面试时会出现的wait和sleep的区别

bit me的博客 1995

【多线程基础】 wait和notify

​线程等待wait()和通知notify(),主要用于多线程之间的通信协作,而且这两个方法都是属于Object类,说明任何对象都可以调用这两个方法。 当在一个实例对象上调用了wait()方法之后,当前线程就会在这个对象上等待。直到另外的线程调用了该对象的notify()方法,处于等待状态的线程才得以继续进行。 这样,多线程之间就可以用这两个方法进行通信协作了。

书生-w的博客 2万+

等待和通知机制(wait和notify)

1. 等待和通知机制的实现 wait() 方法 wait() 是 Object 类的方法,它的作用是使当前执行代码的线程进行等待,该方法将当前线程置入“预执行队列”中,并在 wait() 所在的代码行处停止执行,直到接到通知或者被中断才能继续执行。线程必须获得该对象的对象锁,即只能在同步方法或者同步方法块中调用 wait() 方法,在执行 wait() 方法后,当前线程释放所拥有的对象锁,如果 w...

NULL的博客 1253
上一篇: 数据库中间件:Mycat 权威指南+Mycat 实战笔记,双管齐下!
下一篇: Java:什么是NIO?什么是BIO?NIO 和 BIO 有什么区别?
加班不秃顶
博客等级 码龄7年 1822粉丝 599原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值