为什么wait()、notify()方法需要和synchronized一起使用
提示:更多优秀博文请移步博主的GitHub仓库:GitHub学习笔记、Gitee学习笔记
Obj.wait()与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,与notify必须通过获取的锁对象进行调用**,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){…}语句块内。从功能上来说wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。相应的notify()就是对对象锁的唤醒操作。
1. 不一起使用导致的后果
public class Haha {
public Map<String,String> map=new HashMap<>();
public void haha() throws InterruptedException {
synchronized (map){//使用map加锁
System.out.println("haha method is run");
this.wait();//用当前对象,调用wait方法会报错;正确的写法是map.wait()
}
}
}
public class Test {
public static void main(String[] args) {
new Thread(()->{
try {
new Haha().haha();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
在上述代码中由于Haha类的haha方法中使用map加的锁,但又试图使用this.wait方法释放锁此时会报错:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PMmhumDw-1585273461081)(…/images/7.png)]
2. 为什么要在一起使用
Object.wait(),Object.notify(),Object.notifyAll()都是Object的方法,换句话说,就是每个类里面都有这些方法。
- Object.wait():释放当前对象锁,并进入阻塞队列
- Object.notify():唤醒当前对象阻塞队列里的任一线程(并不保证唤醒哪一个)
- Object.notifyAll():唤醒当前对象阻塞队列里的所有线程
为什么这三个方法要与synchronized一起使用呢?解释这个问题之前,我们先要了解几个知识点
- 每一个对象都有一个与之对应的监视器
- 每一个监视器里面都有一个该对象的锁以及一个等待队列和一个同步队列
wait()方法的语义有两个,一是释放当前对象锁,另一个是进入阻塞队列,可以看到,这些操作都是与监视器相关的,当然要指定一个监视器才能完成这个操作了
notify()方法也是一样的,用来唤醒一个线程,你要去唤醒,首先你得知道他在哪儿,所以必须先找到该对象,也就是获取该对象的锁,当获取到该对象的锁之后,才能去该对象的对应的等待队列去唤醒一个线程。值得注意的是,只有当执行唤醒工作的线程离开同步块,即释放锁之后,被唤醒线程才能去竞争锁。
因wait()而导致阻塞的线程是放在阻塞队列中的,因竞争失败导致的阻塞是放在同步队列中的,notify()/notifyAll()实质上是把阻塞队列中的线程放到同步队列中去
为了便于理解,你可以把线程想象成一个个列车,对象想象成车站,每一个车站每一次能跑一班车,这样理解起来就比较容易了。
值得提的一点是,synchronized是一个非公平的锁,如果竞争激烈的话,可能导致某些线程一直得不到执行。
参考文章:https://blog.csdn.net/qq_39907763/article/details/79301813
为什么wait()、notify()方法需要和synchronized一起使用的更多相关文章
- java 多线程:线程通信-等待通知机制wait和notify方法;(同步代码块synchronized和while循环相互嵌套的差异);管道通信:PipedInputStream;PipedOutputStream;PipedWriter; PipedReader
1.等待通知机制: 等待通知机制的原理和厨师与服务员的关系很相似: 1,厨师做完一道菜的时间不确定,所以厨师将菜品放到"菜品传递台"上的时间不确定 2,服务员什么时候可以取到菜,必 ...
- java多线程详解(6)-线程间的通信wait及notify方法
Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New) ...
- Java 多线程(七) 线程间的通信——wait及notify方法
线程间的相互作用 线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务. Object类中相关的方法有两个notify方法和三个wait方法: http://docs.oracle.com/ ...
- Java使用wait() notify()方法操作共享资源
Java多个线程共享资源: 1)wait().notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写. 2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线 ...
- 并发编程之 wait notify 方法剖析
前言 2018 元旦快乐. 摘要: notify wait 如何使用? 为什么必须在同步块中? 使用 notify wait 实现一个简单的生产者消费者模型 底层实现原理 1. notify wait ...
- Java中wait()和notify()方法的使用
1. wait方法和notify方法 这两个方法,包括notifyAll方法,都是Object类中的方法.在Java API中,wait方法的定义如下: public final void wait( ...
- Java使用wait() notify()方法操作共享资源详解_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 Java多个线程共享资源: 1)wait().notify()和notifyAll()方法是本地方法,并且为final方 ...
- wait/notify方法
执行wait方法会释放锁,执行notify不会释放锁 package com.qf.test05.pojo; /** * @author qf * @create 2018-09-18 10:41 * ...
- 从Guarded Block来看Java中的wait和notify方法
目录 预备知识 概览 线程同步 wait()方法 wait() wait(long timeout) wait(long timeout, int nanos) notify() & noti ...
- 为什么Java中 wait 方法需要在 synchronized 的方法中调用?
另一个棘手的核心 Java 问题,wait 和 notify.它们是在有 synchronized 标记的方法或 synchronized 块中调用的,因为 wait 和 modify 需要监视对其上 ...
随机推荐
- MogDB/openGauss存储过程的修改
MogDB/openGauss 存储过程的修改 SQL 中没有提供显式的存储过程修改命令,通常需要通过 REPLACE 关键字来指定使用当前的存储过程替代之前的同名存储过程. 将前文定义的存储过程替换 ...
- MindSpore编译构建后Vmap模块的RuntimeError问题
技术背景 这篇文章来源于MindSpore仓库中的一个Issue,简单描述问题就是,如果你用MindSpore开发了一个python软件供别人使用,那么很有可能涉及到编译构建的问题.但是如果直接使用编 ...
- k8s之operator
背景 数字经济的兴起推动了云计算.物联网.大数据行业的快速蓬勃发展,对数据中心提出了更高的要求,同时,用户对于数据库运维自动化的需求越来越高,数据库即服务的需求越来越强烈. 随着k8s的普及以及云原生 ...
- Go语言的100个错误使用场景(61-68)|并发实践
目录 前言 9. 并发实践 9.1 context 的不恰当传播(#61) 9.2 开启一个协程但不知道何时关闭(#62) 9.3 在循环中没有谨慎使用协程(#63) 9.4 使用 select 和 ...
- 重新点亮shell————awk函数[十五]
前言 简单介绍一下awk函数. 正文 算术函数 字符串函数 自定义函数 例子: 结 awk就到这里了.
- mysql 必知必会整理—数据汇总与分组[七]
前言 简单整理一下数据汇总与分组 正文 我们经常需要汇总数据而不用把它们实际检索出来,为此MySQL提供了专门的函数.使用这些函数,MySQL查询可用于检索数据,以便分析和报表生成. 这种类型的检索例 ...
- Redis介绍、使用、数据结构和集群模式总结
Redis(Remote Dictionary Server)是一个开源的,基于内存的数据结构存储系统,它支持多种数据结构,如字符串(String).列表(List).集合(Set).有序集合(Sor ...
- JVM简明笔记3:类加载机制
1 类的加载 类的加载指的是将类的 .class 文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class 对象,用来封装类在方法区内的数据结 ...
- 【SQL】将日期时间转换成年月日的日期形式
[SQL]将日期时间转换成年月日的日期形式 这段时间写力扣的SQL题,发现了各式各样的转换时间的方法,正好记录一下 TO_CHAR(XXX,'YYYY-MM-DD') 这个在Oracle应该是很常用的 ...
- IDC:云效产品能力No.1,领跑中国DevOps市场
简介: 近日,全球领先的专业市场调查机构国际数据公司(IDC)发布了<IDC MarketScape:中国 DevOps 平台市场厂商评估,2022>报告.此报告中对中国主流 DevOps ...