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 ...
随机推荐
- Linux shell 及命令汇总
1 文件管理命令 1.cat命令:将文件内容连接后传送到标准输出或重定向到文件 2.chmod命令:更改文件的访问权限 3.chown命令:更改文件的所有者 4.find命令:查找(符合条件)文件并将 ...
- Win32 API翻译
这是从MSDN里面的Win32 SDK API函数.结构.通知.消息等等超过3000个.其中一半是整理自别人翻译. http://files.cnblogs.com/files/sishenzaixi ...
- MySql 学习之路-高级1
Mysql自学之路-高级1 目录: 1.CREATE DATABASE 创建数据库 2.CREATE TABLE 创建数据表 3.INSERT INTO SELECT 把一个表中的数据拷贝到另一个表中 ...
- php分页实现
<?php header("content-type:text/html;charset=utf8"); include 'conn.php'; //每页显示的数据条数 $p ...
- linux上修改mysql登陆密码
1. 修改MySQL的登录设置: # vi /etc/my.cnf 2. 在[mysqld]的段中加上一句:skip-grant-tables 例如: [mysqld] port ...
- 学习笔记《Mustache》模板
Mustache 是一款经典的前端模板引擎,在前后端分离的技术架构下面,前端模板引擎是一种可以被考虑的技术选型,随着重型框架(AngularJS.ReactJS.Vue)的流行,前端的模板技术已经成为 ...
- 使用jprofiler分析dump文件一个实例
3 .dump 线上文件栈 [root@yszyz10a153 ~]# jmap -dump:live,format=b,file=heap201712.hropf 72947 参考:https:/ ...
- Git命令集
安装 Window https://gitforwindows.org/ MAC http://sourceforge.net/projects/git-osx-installer/ git conf ...
- 【学习总结】GirlsInAI ML-diary day-8-list列表
[学习总结]GirlsInAI ML-diary 总 原博github链接-day8 认识list列表 新的数据类型:list. list是一种有序的集合,可以随时添加和删除其中的元素(链表??) 1 ...
- Vue之状态管理(vuex)与接口调用
Vue之状态管理(vuex)与接口调用 一,介绍与需求 1.1,介绍 1,状态管理(vuex) Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态 ...