java 为什么wait(),notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?
wait()
作用:该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止。条件:在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法。进入wait()方法后,当前线程释放锁。在从wait()返回前,线程与其他线程竞争重新获得锁。如果调用wait()时,没有持有适当的锁,则抛出IllegalMonitorStateException
notify()
作用:唤醒其他休眠的线程中的一个,这个线程由系统确定。在调用前,线程也必须要获得该对象的对象级别锁,的如果调用notify()时没有持有适当的锁,也会抛出IllegalMonitorStateException
先回答问题:
(1)为什么wait()必须在同步(Synchronized)方法/代码块中调用?
答:调用wait()就是释放锁,释放锁的前提是必须要先获得锁,先获得锁才能释放锁。
(2)为什么notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?
答:notify(),notifyAll()是将锁交给含有wait()方法的线程,让其继续执行下去,如果自身没有锁,怎么叫把锁交给其他线程呢;(本质是让处于入口队列的线程竞争锁)
下面是正文(详细解释):
之前一直谨记老师教的wait(),notify(),notifyAll()必须要在Synchronized关键中使用,不得其解,现在研究了一下,终于明白了。
首先,要明白,每个对象都可以被认为是一个"监视器monitor",这个监视器由三部分组成(一个独占锁,一个入口队列,一个等待队列)(ps:和AQS的state,同步队列,等待队列好相似)。注意是一个对象只能有一个独占锁,但是任意线程线程都可以拥有这个独占锁。
对于对象的非同步方法而言,任意时刻可以有任意个线程调用该方法。(即普通方法同一时刻可以有多个线程调用)
对于对象的同步方法而言,只有拥有这个对象的独占锁才能调用这个同步方法。如果这个独占锁被其他线程占用,那么另外一个调用该同步方法的线程就会处于阻塞状态,此线程进入入口队列。
若一个拥有该独占锁的线程调用该对象同步方法的wait()方法,则该线程会释放独占锁,并加入对象的等待队列;(为什么使用wait()?希望某个变量被设置之后再执行,notify()通知变量已经被设置。)
某个线程调用notify(),notifyAll()方法是将等待队列的线程转移到入口队列,然后让他们竞争锁,所以这个调用线程本身必须拥有锁。
Synchronized应用举例:生产者消费者模型
消费者线程需要等待直到生产者线程完成一次写入操作。生产者线程需要等待消费者线程完成一次读取操作。假设没有应用Synchronized关键字,当消费者线程执行wait操作的同时,生产线线程执行notify,生产者线程可能在等待队列中找不到消费者线程。导致消费者线程一直处于阻塞状态。那么这个模型就要失败了。所以必须要加Synchronized关键字。
下面这个图是线程的状态图,没有太大关系,可以不看
终于理解了这个图为什么sleep不释放锁,wait释放锁
https://blog.csdn.net/qq_42145871/article/details/81950949
https://blog.csdn.net/qbz_96/article/details/44461645
java 为什么wait(),notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?的更多相关文章
- java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?
在Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity.所有对象的非同步方法都能够在任意时刻被任意线程调用 ...
- .NET中如何在同步代码块中调用异步方法
更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月2日. 在同步代码块中调用异步方法,方法有很多. 一.对于有返回值的Task 在同步代码块中直接访问 Task 的 Result ...
- [转]java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?
在 Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity. 所有对象的非同步 方法都能够在任意时刻被任意线 ...
- Java多线程_wait/notify/notifyAll方法
关于这三个方法,我们可以查询API得到下列解释: wait():导致当前的线程等待,直到其他线程调用此对象的notify( ) 方法或 notifyAll( ) 方法或者指定的事件用完 notify( ...
- wait、notify为什么要放在同步代码块中
等待方遵循的原则: 获取对象的锁,不满足条件就调用wait()方法,条件满足继续执行 通知方原则: 获取对象的锁,改变条件,然后notify 每个对象都有一个监视器锁,这个监视器锁的数据结构如下: w ...
- “全栈2019”Java多线程第十六章:同步synchronized关键字详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java开发笔记(一百)线程同步synchronized
多个线程一起办事固然能够加快处理速度,但是也带来一个问题:两个线程同时争抢某个资源时该怎么办?看来资源共享的另一面便是资源冲突,正所谓鱼与熊掌不可兼得,系统岂能让多线程这项技术专占好处?果然是有利必有 ...
- Java多线程6:Synchronized锁代码块(this和任意对象)
一.Synchronized(this)锁代码块 用关键字synchronized修饰方法在有些情况下是有弊端的,若是执行该方法所需的时间比较长,线程1执行该方法的时候,线程2就必须等待.这种情况下就 ...
- 【面试普通人VS高手系列】讲一下wait和notify这个为什么要在synchronized代码块中?
一个工作七年的小伙伴,竟然不知道"wait"和"notify"为什么要在Synchronized代码块里面. 好吧,如果屏幕前的你也不知道,请在评论区打上&qu ...
随机推荐
- Kafka 安装配置 windows 下
Kafka 安装配置 windows 下 标签(空格分隔): Kafka Kafka 内核部分需要安装jdk, zookeeper. 安装JDK 安装JDK就不需要讲解了,安装完配置下JAVA_HOM ...
- windows下php7.1安装redis扩展以及redis测试使用全过程
最近做项目,需要用到redis相关知识.在Linux下,redis扩展安装起来很容易,但windows下还是会出问题的.因此,特此记下自己实践安装的整个过程,以方便后来人. 一,php中redis扩展 ...
- Python面试笔记四
数据库 1.将name字段添加索引 create index index_emp_name on student(name); 2.查询女生中数学成绩最高的分数 select max(score) f ...
- SQLServer之创建主XML索引
创建主XML索引注意事项 若要创建主 XML 索引,请使用 CREATE INDEX (Transact-SQL) Transact-SQL DDL 语句. XML 索引不完全支持可用于非 XML 索 ...
- docker容器日志收集方案(方案四,目前使用的方案)
先看数据流图,然后一一给大家解释 这个方案是将日志直接从应用代码中将日志输出到redis中(注意,是应用直接连接redis进行日志输出),redis充当一个缓存中间件有一定的缓存能力,不过有限,因 ...
- CSS---文档流布局 | 脱标-postion-zindex | 脱标-浮动
一.css文档流布局概念 1.1,什么是标准文档流 1.2,标准文档流下有哪些微观现象 二.CSS---position属性 2.1,position:relative 2.2,position:fi ...
- RESTful API规范
1. 域名 应该尽量将API部署在专用的域名下. https://api.example.com 如果确定API简单,不会有进一步的括在,可以考虑放在主域名之下. https://example.or ...
- 数据库【mysql】之pymysql
安装模块 pip install pymysql 导入模块 import pymysql 创建链接 conn = pymysql.connect(host=') 创建索引 cursor = conn. ...
- SystemTap Beginners Guide
SystemTap 3.0 SystemTap Beginners Guide Introduction to SystemTap Edition 3.0 Red Hat, Inc. Don Do ...
- koa2--delegates模块源码解读
delegates模块是由TJ大神写的,该模块的作用是将内部对象上的变量或函数委托到外部对象上.然后我们就可以使用外部对象就能获取内部对象上的变量或函数.delegates委托方式有如下: gette ...