使用wait/notify实现线程间的通信

SikuliX实战:5分钟搞定游戏挂机脚本(附防检测思路与Python集成技巧) 本文详细介绍了如何使用SikuliX快速开发游戏挂机脚本,包括环境配置、基础原理、防检测策略及Python集成技巧。通过实战案例展示如何实现自动化任务、高级防检测方案,并结合Python提升脚本性能与智能度,帮助玩家高效完成重复性游戏操作。 阅读详情

之前对Java多线程中的wait/notify机制理解都不是很清晰,最近看了一本技术书,通过里面的讲解再配上一些博客,终于算是对wait/notify有了进一步的理解。

下面就来说说我对这两个方法的认识:

都知道在Java中,我们可以通过继承Thread或者实现Runnable接口来实现多线程,这些线程会各自执行自己的任务,但是一个人的力量是有限的,一个线程的力量也是有限的,要想使系统各部分配合得更好,我们需要实现各个线程间的通信。要实现线程间的通信最好的方法就是使用wait/notify机制。

这里有两个新问题:

  1. 什么是线程间的通信?
  2. 如何使用wait/notify机制实现线程间的通信?

为了解决这两个问题,我们来看看下面这段代码:

public class ThreadA extends Thread{
    private MyList list;
    public ThreadA(MyList list) {
        this.list = list;
    }
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            list.add();
            System.out.println("第  "+i+" 此执行add操作");
        }
    }
    public static void main(String[] args) {
        MyList list = new MyList();
        ThreadA a = new ThreadA(list);
        ThreadB b = new ThreadB(list);
        a.start();
        b.start();
    }
}

class ThreadB extends Thread{
    private MyList list;
    public ThreadB(MyList list) {
        this.list = list;
    }
    @Override
    public void run() {

        while( true ) {
            if (list.size() == 3) {
                System.out.println("线程Thread检测到list中的长度变为3了,停止该线程");
                Thread.interrupted();
            }
        }
    }
}
class MyList{
    private ArrayList<String> list = new ArrayList<String>();
    public void add() {
        list.add("abc");
    }
    public int size() {
        return list.size();
    }
}

执行结果如下:

第 0 此执行add操作
第 1 此执行add操作
第 2 此执行add操作
线程Thread检测到list中的长度变为3了,停止该线程
第 3 此执行add操作
第 4 此执行add操作

在上面的例子中实现了两个线程,其中线程ThreadA的任务是向list中添加值,而线程ThreadB的任务是监听list中的数量,一旦list的长度达到了3,就通过interrupted方法停止该线程的监听操作。

在这里线程ThreadA与线程ThreadB就实现了通信,这个例子中的通信指的就是:线程ThreadA执行向list添加值的操作,而线程ThreadB通过不断的执行while监听来观察线程ThreadA的操作,从而做出自己相应的操作。可是这种通信方式有一个弊端,线程ThreadB需要不断的执行while循环来达到监听的目的,这样对CPU的资源会产生浪费。服务端的资源是非常宝贵的,所以就出现了wait/notify机制来解决这个问题。

我们看看使用wait/notify机制后,上面的线程间通信会变成什么样?


public class ThreadA extends Thread{
    private MyList list;
    public ThreadA(MyList list) {
        this.list = list;
    }
    @Override
    public void run() {
        synchronized (list) {
            for (int i = 0; i < 5; i++) {
                list.add();
                System.out.println("第  "+i+" 此执行add操作");
                    try {
                        if (list.size() == 3) 
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }
        }
    }
    public static void main(String[] args) {
        MyList list = new MyList();
        ThreadA a = new ThreadA(list);
        ThreadB b = new ThreadB(list);
        a.start();
        b.start();
    }
}
class ThreadB extends Thread{
    private MyList list;
    public ThreadB(MyList list) {
        this.list = list;
    }
    @Override
    public void run() {
        synchronized (list) {
            System.out.println("线程Thread检测到list中的长度变为3了,停止该线程");    
            list.notify();  
            System.out.println("notify方法调用结束");
        }
    }
}
class MyList{
    private ArrayList<String> list = new ArrayList<String>();
    public void add() {
        list.add("abc");
    }
    public int size() {
        return list.size();
    }
}

执行结果如下:

第 0 此执行add操作
第 1 此执行add操作
第 2 此执行add操作
线程Thread检测到list中的长度变为3了,停止该线程
notify方法调用结束
第 3 此执行add操作
第 4 此执行add操作

上面是使用了wait/notify机制后的代码实现,两种方式的执行结果相同。但是代码的实现方式却大有不同,可以看到线程ThreadB里没有了while循环,说明在该线程里不用一直监听list中的值了,所以资源浪费的问题得到了解决,这其中的原理是什么呢?

首先需要注意的一点是,wait/notify方法必须存在于同步代码块里,因为这两个方法需要由锁对象去调用,在上面的例子中锁对象是list,调用wait与notify的方法都是同一个锁对象,具体用意在下面再讲。

然后我们来仔细说说代码的执行流程,首先我们先启动的是a线程,a线程拿到锁对象list,进入该线程run方法中的同步代码块,执行for循环,for循环中一直执行add添加操作,并进行if判断,当执行到第三次的时候进入if判断,执行list.wait(),当执行完这一句代码,当前线程立即释放list锁对象,由于此时,b线程也在等待同一把锁对象,所以该线程的拿到锁对象后执行对应的同步代码块内的内容。

当执行完list.notify()后,线程b会唤醒线程a,使其处于runnable状态,一旦抢到锁对象后立即接着list.wait()后的代码执行,与list.wait()不同的是,线程b在执行完list.notify()后没有立即释放锁,而是在执行完同步代码块中的所有内容后,锁才会被释放,锁被释放后,由于线程a已经被notify唤醒,所以会接着上次的地方执行。


在使用等待/唤醒机制的时候,有几个需要注意的地方。

  • 一个notify()方法只会唤醒一个处于等待中的线程,要想唤醒所有,可以使用notifyAll()方法
  • notify()方法只会唤醒被同一个锁对象wait()的线程。

对于第二点,如果我们将ThreadB修改成这样:

class ThreadB extends Thread{
    private MyList list;
    public ThreadB(MyList list) {
        this.list = list;
    }
    @Override
    public void run() {
        synchronized (this) {
            System.out.println("线程Thread检测到list中的长度变为3了,停止该线程");
            this.notify();
            System.out.println("notify方法调用结束");
        }
    }
}

执行结果如下,并且程序一直没有停止,可见线程a没有被唤醒。

第 0 此执行add操作
第 1 此执行add操作
第 2 此执行add操作
线程Thread检测到list中的长度变为3了,停止该线程
notify方法调用结束

这是因为调用notify与wait方法不是使用的同一个锁对象,可以理解为这两个notify和wait不是一对,所以没达到唤醒的目的。


总结

经过对比发现,我发现wait/notify机制更像是一种主动推送的实现,一旦A线程达到了某种状态,可以通过wait方法来通知与A线程使用同一个锁对象的线程,让他们去做相应的操作,由于只有一把锁,所以只能有一个线程获得执行机会,这个获得执行机会的线程肯定是在A线程中达到某种状态后才会执行,所以也就间接实现了通信的目的。

矿石生成(1) 这个提供了标准化的矿石放置配置模板简化了常见和稀有矿石的配置过程遵循了Minecraft原版的世界生成模式提高了代码的可读性和可维护性通过使用这个类,模组开发者可以更轻松地配置矿石的生成规则,而不需要每次都手动编写完整的放置修饰符列表。这种设计模式在原版Minecraft和其他大型模组中也很常见,是一种良好的编程实践。// 导入语句...// 字段和方法...包声明表明这个类位于luckymod模组的WorldGen包中,专门处理世界生成相关配置。导入语句。 阅读详情

相关推荐

揭秘Synopsys EDA中的AI黑科技:DSO.ai如何改变传统芯片设计流程

本文深入探讨了Synopsys EDA中的AI黑科技DSO.ai如何革新传统芯片设计流程。通过数据驱动的方法论、功耗优化革命和时序收敛智能加速,DSO.ai显著提升了设计效率和质量,实现了从经验驱动到AI驱动的范式转变。文章还提供了实战指南,帮助团队跨越AI EDA的实施鸿沟。

weixin_29296241的博客 525

详细解析wait/notify

关于wait和notify

m0_62609939的博客 1358

纽马克-贝塔法(Newmark-Beta Method)在结构动力学中的应用与实现

本文深入解析了纽马克-贝塔法(Newmark-Beta Method)在结构动力学数值计算中的核心原理与应用。作为经典的时间积分算法,它通过调节γ和β参数,在计算精度、稳定性与效率间取得平衡,尤其适用于地震响应、风振分析等工程场景。文章详细阐述了其数学内核、在有限元分析中的实现步骤,并对比了隐式与显式方案的适用场景,为工程师提供了关键的方法选择与参数调优指导。

weixin_29232121的博客 148

wait和notify原理

文章目录1.wait和notify1.1 小故事1.2 原理1.3 API介绍obj.wait() 和 obj.notify()sleep(long n)和 wait(long n) 的区别2.wait/notify的正确使用3.关于wait与notify和notifyAll方法的总结 1.wait和notify 1.1 小故事 1.2 原理 1.当前线程必须拥有此对象的monitor监视器(锁)。 2.当前线程调用wait()方法,线程就会释放此锁的所有权,并等待 3.直到另一个线程通过调用noti

张大安的博客 1993

echarts如何实现3D饼图(环形图)?

自定义修改3D饼图的宽高和legend

i-cat的博客 1万+

USRP N210与MATLAB连接实战:从驱动安装到信号接收

本文详细介绍了USRP N210与MATLAB连接的完整流程,涵盖驱动安装、网络配置、支持包安装及信号接收实战。重点解决了安装过程中的常见错误和硬件连接问题,并通过MATLAB代码示例展示了如何配置接收器、处理信号数据,帮助用户快速实现从设备对接到信号分析的全过程。

blue的专栏 819

一篇文章带你彻底搞懂wait/notify

wait、notify以及条件变量的深入学习。

aaaPostcard的博客 1816

Python爬虫实战:如何爬取京东商品评论数据

在本文中,我们介绍了如何使用 Python 爬虫技术爬取京东商品的评论数据。首先,我们分析了京东商品评论的 API 接口和 JSON 数据结构,然后编写了爬虫程序来抓取评论数据,并将数据保存到 CSV 文件中。接着,我们进行了一些基本的数据分析,包括评分分布和简单的情感分析。爬取京东商品评论的数据可以为电商分析、情感分析等提供有价值的信息。你可以在此基础上进行更深入的分析,挖掘更多的商业价值。希望本篇教程能够帮助你了解如何利用 Python 进行电商数据的爬取和分析!

2201_76125261的博客 1647

wait和notify的功能和使用注意事项

notify函数也是object实现的方法,哪个对象调用notify就是唤醒一个正在那个对象上wait的线程,notify也要在synchronized修饰的方法或者代码块里调用,调用的对象也是被加锁的对象。wait和notify就是控制线程执行顺序的两个方法,这两个方法是基础父类Objec的成员方法,所以所有的类都能调用这个两个方法;(2)sleep方法被唤醒是通过中断调用异常唤醒,本质上是错误逻辑,wait方法被唤醒是正常的函数调用,并没有发生错误;第一:释放调用wait方法对象的锁。

qq_61925446的博客 1029

Python爬虫实战:全自动采集银行理财产品收益率数据

本文通过Playwright动态爬虫技术,成功实现了对银行理财产品收益率数据的实时采集,并通过 Pandas 数据清洗、SQLite 存储、调度自动化等模块,构建了一个可扩展的银行理财数据抓取系统。理财非儿戏,数据做决策。掌握银行收益信息是我们迈向理性投资的第一步。希望这套工具对你有所帮助!

2201_76125261的博客 1155

SpringBoot集成auth0-jwt插件,实现jwt的token生成、校验,用户登录验证,配置拦截器拦截请求校验token功能

该文章介绍了SpringBoot如何集成auth0-jwt插件,实现jwt的token生成、校验,用户登录验证,配置拦截器拦截请求校验token功能. JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。它以JSON对象的形式存在,并使用数字签名来验证信息的完整性和真实性。JWT由三部分组成,分别是Header、Payload和Signature。

yunnuo的博客 1246

【面试:并发篇16:多线程:wait/notify详解】原理及错误用法(虚假唤醒等)

我们之前学习的过程中浅显的了解过wiat/notify,但是没有系统的介绍过wait/notify,wait是使线程陷入等待notify是随机唤醒一个被wait的线程。obj.wait()wait方法让进入object监视器的线程到waitSet等待。wait后会释放对象锁,让其他线程竞争wait的有时限方法,如果在时限内没有其他线程唤醒,则自己直接唤醒自己,若期间有别的线程唤醒那就正常唤醒。wait后会释放对象锁,让其他线程竞争notify方法让正在waitSet等待的线程挑一个唤醒结果解释。...

m0_71229547的博客 1035

企业合规审查系统开发实战:基于知识图谱与深度学习的智能引擎构建(附完整Python代码)

动态合规监测:实时追踪法规变化并更新知识库智能合约审计:区块链智能合约的自动合规检查跨域知识融合:整合财务、法律、业务多维度数据可解释性增强:基于Attention机制生成合规审查依据。

理论都是虚的,代码才是王道。 456

使用wait/notify实现线程间通信

线程与线程之间不是独立的个体,他们彼此之间都是可以相互通信和协作的。比如有两个线程A和B,线程A做的是不断地对变量i进行累加,B做的通过while循环,当检测到i的值是10000时则打印出来,这样两个线程实现了通信,但是线程B不停地通过while语句轮询机制来检测某一个条件,这样会浪费CPU资源。因此我们需要一种机制来减少CPU的资源浪费而且还可以实现多个线程之间的通信,即“wait/notify

NEU_tt的博客 1059

Statistics and Machine Learning Toolbox

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

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

【Java并发编程】之十:使用wait/notify/notifyAll实现线程间通信的几点重要说明

在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用notify()方法或notifyAll()方法,将通知其他线程从wait()方法处返回。 Object是所有类的超类,它有5个方法组成了等待/通知机制的核心:notify()、notifyAll()、wait()、wait(

兰亭风雨的专栏 2万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

[Java 多线程技术](七)使用wait/notify实现线程间通信

线程是操作系统中独立的个体,但这些个体如果不经过特殊处理就不能成为一个整体。线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更加强大,在大大提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控和监督。 1. 等待通知机制 1.1 不使用等待/通知机制实现线程间通信   创建新项目,在实验中使用sleep()结合while(true)死循环法来实现多个线程间通信。代码如下: public class MyList { priva.

YHJ 2404

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

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

第十篇:使用wait/notify/notifyAll实现线程间通信的几点重要说明

在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用notify()方法或notifyAll()方法,将通知其他线程从wait()方法处返回。       Object是所有类

u012426327的专栏 334

【并发】使用wait/notify/notifyAll实现线程间通信的几点重要说明

【并发】使用wait/notify/notifyAll实现线程间通信的几点重要说明 在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用...

201

使用wait/notify/notifyAll实现线程间通信的几点重要说明

在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用notify()方法或notifyAll()方法,将通知其他线程从wait()方法处返回。 Object是所有类的...

weixin_33819479的博客 90

java挑战高并发 之(10):使用wait/notify/notifyAll实现线程间通信的几点重要说明

在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用notify()方法或notifyAll()方法,将通知其他线程从wait()方法处返回。       Object

做事要专心 1284

java 多线程&不使用wait/notify机制实现线程间通信——60

使用sleep()结合while(true)死循环法来实现多个线程间的通信。 对变量: volatile private List list = new ArrayList(); 添加volatile关键字,以实现A线程和B线程间的可视性 虽然两个线程间实现了通信,但缺点是线程ThreadB.java不停地通过while语句轮询机制来检测 某一个条件,这样会浪费CPU资源。 如果轮询的时间间隔很小,则更浪费CPU资源; 如果轮询的时间间隔很大,则有可能取不到想要的数据。 wait/notify(等待/通知

爱的叹息的专栏 348

【Java并发编程】:使用wait/notify/notifyAll实现线程间通信

在java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用notify()方法或notifyAll()方法,将通知其他线程从wait()方法处返回。 Object是所有类的超类,...

weixin_30907523的博客 84

【Java并发编程】:使用wait/notify/notifyAll实现线程间通信的几点重要说明

在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用notify()方法或notifyAll()方法,将通知其他线程从wait()方法处返回。       Object是所有类

GY的的专栏 547

【Java并发编程】使用wait/notify/notifyAll实现线程间通信的几点重要说明

在 Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用 wait()方法,将...

哲洛不闹的专栏 120
上一篇: SpringBoot整合日志框架LogBack
下一篇: C语言指针学习总结
KKSJS
博客等级 码龄9年 16粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值