深入理解Java多线程中的 wait() 和 notify():为何要与 synchronized 手牵手

在Java中,wait、notify方法通常与synchronized关键字一起使用,这样做有几个重要的原因,主要涉及线程的协调和正确的并发控制。以下是一些关键点:

  1. 监视器锁(Monitor Lock)

    • 每个对象在Java中都可以作为一个监视器锁,用来管理对该对象的同步访问。当一个线程持有一个对象的监视器锁时,其他线程无法同时获取这个锁。
    • wait方法必须在持有监视器锁的情况下调用,也就是说,wait方法必须在synchronized块或synchronized方法中调用。调用wait方法的线程会放弃该对象的监视器锁,同时进入等待状态,直到另一个线程调用同一对象上的notifynotifyAll方法。
  2. 释放锁和等待

    • 当一个线程调用对象的wait方法时,它会释放该对象的监视器锁,并等待被唤醒。如果没有synchronized关键字保证线程在调用wait方法时已经持有锁,就无法确保线程在进入等待状态前不会与其他线程发生竞争条件(race condition)。
    • 只有持有监视器锁的线程才能调用wait方法,这样可以确保在进入等待状态之前不会有其他线程修改共享资源,从而避免不一致的状态。
  3. 线程协调

    • waitnotifynotifyAll方法提供了一种线程间通信的机制,使得一个线程可以通过这些方法来通知其他线程某些条件已经满足。
    • synchronized关键字确保了只有一个线程能够在某个时间段内执行持有相同监视器锁的代码,从而避免多个线程同时修改共享资源导致的数据不一致问题。

简而言之,wait方法需要与synchronized一起使用,以确保线程在进入等待状态之前,已经安全地获取了监视器锁,并且在被唤醒后能够重新获得锁。这种机制确保了线程间的协调和共享资源的一致性。

举个简单的例子说明:

class SharedResource {private boolean condition = false;public synchronized void waitForCondition() throws InterruptedException {while (!condition) {wait();}// do something after condition is true}public synchronized void changeCondition() {condition = true;notify(); // or notifyAll();}
}

在这个例子中,waitForCondition方法使用synchronized关键字来获取锁,然后调用wait方法。当changeCondition方法改变条件并调用notifynotifyAll方法时,等待的线程将被唤醒并继续执行,同时它们会重新获取锁。

再写一段代码

/*** 功能描述:  Java多线程中的 wait() 和 notify() 方法* @author Songxianyang* @date 2024-06-25 17:38*/
public class WaitNotify {public void waitTest(Object lock) throws InterruptedException {synchronized (lock) {lock.wait();System.out.println("线程等待!!!释放锁等待----"+Thread.currentThread().getName());}}@SneakyThrowsprivate void notifyTest(Object lock) {synchronized (lock) {// lock.notify();lock.notifyAll();System.out.println("唤醒线程呀哈哈哈---(唤醒其中一个线程,去枪锁)"+Thread.currentThread().getName());TimeUnit.SECONDS.sleep(2);}}public static void main(String[] args) {Object lock = new Object();Thread thread = new Thread(()->{WaitNotify waitNotify = new WaitNotify();try {waitNotify.waitTest(lock);} catch (InterruptedException e) {e.printStackTrace();}},"线程1");thread.start();Thread thread2 = new Thread(()->{WaitNotify waitNotify = new WaitNotify();try {waitNotify.waitTest(lock);} catch (InterruptedException e) {e.printStackTrace();}},"线程2");thread2.start();Thread thread3 = new Thread(()->{WaitNotify waitNotify = new WaitNotify();waitNotify.notifyTest(lock);},"线程3");thread3.start();}
}

上面得例子可得:

  • 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。

  • 如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 “先来后到”)

  • 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/35673.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树 遍历迭代法

二叉树 遍历迭代法 Leetcode 94 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), rig…

一个产品需求工程师繁忙的一天

早晨:开启新的一天 7:00 AM - 起床 早晨七点准时起床。洗漱、早餐后,查看手机上的邮件和消息,提前了解今天的工作安排和优先事项。 8:00 AM - 前往公司 坐地铁前往公司。在地铁上,习惯性地阅读一些行业资讯和市场报告&#xff0…

使用SpringBoot整合Servlet

一、SpringBoot和Servlet的整合 1、用注解WebServlet配置Servlet映射 创建一个SpringBoot的web工程,在工程用创建一个Servlet 2、在SpringBoot的启动类上加注解ServletComponentScan 二、额外的方式 1、不使用WebServlet配置Servlet映射 创建一个SpringBoot工…

RabbitMQ延时队列(实现定时任务)

消息的TTL(Time To Live)就是消息的存活时间。 RabbitMQ可以对队列和消息分别设置TTL。 对队列设置存活时间,就是队列没有消费者连着的保留时间。 对每一个单独的消息单独的设置存活时间。超过了这个时间,我们认为这个消息就死了,称之为死…

代码随想录算法训练营:19/60

非科班学习算法day19 | LeetCode530:二叉搜索树的最小绝对差 ,Leetcode501:二叉搜索树的众数 ,Leetcode236:二叉树的最近公共祖先 目录 介绍 一、LeetCode题目 1.LeetCode530:二叉搜索树的最小绝对差 题目解析 2.Leetcode501: 二叉搜索树的众数 …

软设之加工逻辑之结构化语言

结构化语言是一种介于自然语言和形式化语言之间的半形式语言,是自然语言的一个受限子集 外层:用来描述控制结构,采用顺序,选择和重复3种基本结构 1.顺序结构:一组祈使语句,选择语句,重复语句的…

个人对JVM的一点理解

JVM(Java 虚拟机)是 Java 程序能够跨平台运行的关键。它负责将 Java 字节码转换为机器码并执行。 JVM 主要由类加载器、运行时数据区、执行引擎和本地方法接口等部分组成。运行时数据区包括方法区、堆、虚拟机栈、本地方法栈和程序计数器等。 GC&#xf…

远期利率(Forward Rate)是什么?以及远期利率在期货合约中的应用

远期利率是什么? 中文版 远期利率(Forward Rate)是指从未来某一时间段开始适用的利率。它是金融市场上的一种合约利率,表示在某个特定日期开始的一段时间内的预期利率。这种利率可以通过现有的即期利率(Spot Rate&am…

6.26考试前总结

一、选择 1、运算符重载:(1)不可重载:. .* :: ?: sizeof (2)只成员函数:、[]、()、-> ps:和[]需要加&,返回类,[]返回中括号内…

SpringBoot根据不同IP限制接口的QPS

根据对方IP地址来限制接口的QPS(每秒查询率),你可以结合Spring Boot应用、Guava的RateLimiter或者自定义的并发控制逻辑来实现。以下是一个基于Guava RateLimiter和Spring Boot的示例,展示如何根据IP地址来限制接口的QPS&#xff…

镜头下的光学

说实话,当我看到几何光学的内容全是初中的解析几何的时候,我就觉得讲的方式太原始了,而且太过复杂也看不懂。所以我尝试做了数学建模,发现建模之后模型可以解释一些物理现象,也不会有矛盾的地方,那就算过得…

【Python系列】探索 Python 环境管理工具:conda 与 pip 的比较

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

简过网:专科生可以考的编制岗位有哪些?这5个铁饭碗要抓住了!

专科生可以考的编制岗位有哪些?以下这几种可以考的,尤其是应届毕业生,一定要抓住机会哦! ​ 一、三支一扶:专科生可报考,期满可转编。 三支一扶:支农、支医生、支教、扶贫 工作时间一般为2年&…

深入探索Postman:前置与后置脚本的编写与应用

Postman是一款广受欢迎的API开发和测试工具,它提供了丰富的功能来简化接口测试过程。在Postman中,前置脚本(Pre-request Script)和后置脚本(Tests Script)是两个强大的功能,允许用户在发送请求之…

秋招Java后端开发冲刺——非关系型数据库篇(Redis)

一、非关系型数据库 1. 主要针对的是键值、文档以及图形类型数据存储。 2. 特点: 特点说明灵活的数据模型支持多种数据模型(文档、键值、列族、图),无需预定义固定的表结构,能够处理各种类型的数据。高扩展性设计为水…

安全技术和防火墙(一)

安全技术和防火墙 安全技术 入侵检测系统:特点是不阻断网络访问,主要提供报警和事后监督 不主动介入 (监控) 入侵防御系统:透明模式工作 ,数据包,网络监控,服务攻击,木马,蠕虫,系统漏洞 等 进行准确的分析判断 判断为攻击行为后会…

高校心理咨询管理系统

摘 要 随着高校学生心理问题的增多,心理咨询服务在高校中的重要性日益凸显。然而,传统的心理咨询管理方式存在着诸多问题,如信息不透明、咨询师资源不足等。为了解决这些问题,本文设计并实现了一种基于Java Web的高校心理咨询管理…

model_json_schema

model_json_schema示列 from pydantic import BaseModel, Field, ValidationError, field_validatorclass User(BaseModel):id: int Field(default0, lt100, gt0)username: stremail: strfield_validator(username)def name_must_alpha(cls, v):assert v.isalpha(), name mus…

浸式冷却设计参数

每天一篇行业发展资讯,让大家更及时了解外面的世界。 更多资讯,请关注B站/公众号【莱歌数字】,有视频教程~~ 两相被动浸入冷却是指使用改变相的沸腾液体来去除一个或多个表面的热量的冷却系统。 然后蒸汽被移动到冷凝器,然后被…

LaTeX中添加矩阵分块虚线并设置虚线疏密

对于大型矩阵,有时需要添加分块虚线。 方法为使用arydshln宏包,然后在array环境中设置虚线。需要注意的是,使用矩阵环境需要搭配amsmath宏包使用,且需放在amsmath宏包之后。即导言区设置为 \usepackage{amsmath} \usepackage{ary…