在 Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity。

  所有对象的非同步 方法都能够在任意时刻被任意线程调用,此时不需要考虑加锁的问题。

  而对于对象的同步方法来说,在任意时刻有且仅有一个拥有该对象独占锁的线程能够调用它们。例如,一个同步方法是独占的。如果在线程调用某一对象的同步方法时,对象的独占锁被其他线程拥有,那么当前线程将处于阻塞状态,并添加到对象的入口队列中。

  只有在调用线程拥有某个对象的独占锁时,才能够调用该对象的wait(),notify()和notifyAll()方法。如果尝试在未获取对象锁时调用这三个方法,那么你将得到一 个"java.lang.IllegalMonitorStateException:current thread not owner"。
当一个线程正在某一个对象的同步方法中运行时调用了这个对象的wait()方法,那么这个线程将释放该对象的独占锁并被放入这个对象的等待队列,(JZ:意味着其他线程也可以再次调用同一个对象的wait方法)
  注意,wait()方法强制当前线程释放对象锁。这意味着在调用某对象的wait()方法之前,当前线程必须已经获得该对象的锁。因此,线程必须在某个对象的同步方法或同步代码块中才 能调用该对象的wait()方法。  
  当某线程调用某对象的 notify()或notifyAll()方法时,任意一个(对于notify())或者所有(对于notifyAll())在该对象的等待队列中的线程,将被转移到该对象的入口队列。接着这些队列(译者注:可能只有一个)将竞争该对象的锁,最终获得锁的线程继续执行。
如果没有线程在该对象的等待队列中等待获得锁,那么notify()和notifyAll()将不起任何作用。在调用对象的notify()和notifyAll()方法之前,调用线程必须已经得到该对象的锁。因此,必须在某个对象的同步方法或同步代码块中才能调用该对象的notify()或notifyAll()方法。
  对于处于某对象的等待队列中的线程,只有当其他线程调用此对象的notify()或notifyAll()方法时才有机会继续执行。
 
  调用wait()方法的原因通常是,调用线程希望某个特殊的状态(或变量)被设置之后再继续执行。调用notify()或notifyAll()方法的原因通常是,调用线程希望告诉其他等待中的线程:"特殊状态已经被设置"。这个状态作为线程间通信的通道,它必须是一个可变的共享状态(或变量)。
例如,生产者线程向缓冲区中写入数据,消费者线程从缓冲区中读取数据。消费者线程需要等待直到生产者线程完成一次写入操作。生产者线程需要等待消费者线程完成一次读取操作。假设wait(),notify(),notifyAll()方法不需要加锁就能够被调用。
此时消费者线程调用wait()正在进入状态变量的等待队列(译 者注:可能还未进入)。在同一时刻,生产者线程调用notify()方法打算向消费者线程通知状态改变。那么此时消费者线程将错过这个通知并一直阻塞。因此,对象的wait(),notify(),notifyAll()方法必须在该对象的同步方法或同步代码块中被互斥地调用。
[JZ]:这也是多线程编程里的一个景点问题,线程A进行锁操作的过程是非原子的,线程B就进行了释放的请求,导致线程A申请锁后无法释放!
 
转载:http://m.blog.csdn.net/blog/qilixiang012/44524561
 
以下为我的测试代码:
/**
* Created by joe on 2015/8/4.
*/
public class maintest {
public static void main(String[] args){
doSync();
} private synchronized static void doSync() {
testClass tc = new testClass();
MyThread myThread = new MyThread(tc); for (int i = 0; i < 10; i++) {
new Thread(myThread).start();
}
try {
Thread.sleep(3000, 0);
} catch (InterruptedException e) {
e.printStackTrace();
}
tc.set();
} }
class MyThread implements Runnable{
private int count=0;
private testClass tc;
public MyThread(testClass tc) {
this.tc = tc; } @Override
public void run() {
System.out.println("try to wait in MyThread"+ ++count);
tc.get();
System.out.println("after wait in MyThread" + count); }
}
class MyThread1 implements Runnable{
private int count=0; @Override
public void run() {
count++;
}
}
class testClass{
public synchronized void get(){
try {
System.out.println("try to wait");
this.wait();
System.out.println("after wait"); } catch (InterruptedException e) {
e.printStackTrace();
}
return;
}
public synchronized void set(){
this.notifyAll();
}
}

[转]java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?的更多相关文章

  1. java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?

    在Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity.所有对象的非同步方法都能够在任意时刻被任意线程调用 ...

  2. java 为什么wait(),notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?

    wait()作用:该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止.条件:在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法.进入wai ...

  3. 为什么 wait()方法和 notify()/notifyAll()方法要在同步块 中被调用 ?

    这是 JDK 强制的,wait()方法和 notify()/notifyAll()方法在调用前都必须先获得对 象的锁

  4. Java多线程_wait/notify/notifyAll方法

    关于这三个方法,我们可以查询API得到下列解释: wait():导致当前的线程等待,直到其他线程调用此对象的notify( ) 方法或 notifyAll( ) 方法或者指定的事件用完 notify( ...

  5. 【面试普通人VS高手系列】讲一下wait和notify这个为什么要在synchronized代码块中?

    一个工作七年的小伙伴,竟然不知道"wait"和"notify"为什么要在Synchronized代码块里面. 好吧,如果屏幕前的你也不知道,请在评论区打上&qu ...

  6. wait、notify为什么要放在同步代码块中

    等待方遵循的原则: 获取对象的锁,不满足条件就调用wait()方法,条件满足继续执行 通知方原则: 获取对象的锁,改变条件,然后notify 每个对象都有一个监视器锁,这个监视器锁的数据结构如下: w ...

  7. “全栈2019”Java第四十二章:静态代码块与初始化顺序

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. JAVA 7新特性——在单个catch代码块中捕获多个异常,以及用升级版的类型检查重新抛出异常

    在Java 7中,catch代码块得到了升级,用以在单个catch块中处理多个异常.如果你要捕获多个异常并且它们包含相似的代码,使用这一特性将会减少代码重复度.下面用一个例子来理解. Java 7之前 ...

  9. Java多线程--wait(),notify(),notifyAll()的用法

    忙等待没有对运行等待线程的 CPU 进行有效的利用(而且忙等待消耗cpu过于恐怖,请慎用),除非平均等待时间非常短.否则,让等待线程进入睡眠或者非运行状态更为明智,直到它接收到它等待的信号. Java ...

随机推荐

  1. Java 中的四种权限修饰符

    * * private: * Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”. * 被其修饰的属性以及方法只能被该类的对象 访问,其子类不能访问,更不能允许跨包访问. * * def ...

  2. 1、Vue 实战-入门篇

    先决条件:需要 Node.js . npm 基础. 如果没有基础看先看下面简单的两点介绍. 1.npm 命令介绍. 1.所有命令  -h 可以查看.也可以从官网查 docs,结果如下. --help ...

  3. 【xinsir】webpack实践

    webpack现在是前端必会的技能了,也是在工作中必定用到的.所以,如果我们现在还不会webpack,那么在将来面试中肯定会被扣分的. webpack中文官网:https://www.webpackj ...

  4. dp-完全背包(题)

    理解了这道题 , 我感觉对背包又有了一个更深的认识 …… HDU  2159 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务.久而久之xhd开始对杀怪产生的厌恶感, ...

  5. flask模板 flask-bootstrap

    1.模板 a.block块中继承前面block块的内容,需要添加{{super()}} b.macro 宏:   作用:在模板中定义函数(定义函数->注意添加()->可以使用from 模板 ...

  6. Elasticsearch:是什么?你为什么需要他?

    Elasticsearch 是什么? Elasticsearch 是一个分布式的.开源的搜索分析引擎,支持各种数据类型,包括文本.数字.地理.结构化.非结构化. Elasticsearch 是基于 A ...

  7. influxdb的命令们

    InfluxDB是一个开源的时序数据库,使用GO语言开发,特别适合用于处理和分析资源监控数据这种时序相关数据.而InfluxDB自带的各种特殊函数如求标准差,随机取样数据,统计数据变化比等,使数据统计 ...

  8. java面试| 精选基础题(3)

    每天进步一点点,距离大腿又近一步! 阅读本文大概需要6分钟 系列文章 java面试| 精选基础题(1) java面试|精选基础题(2) 1.float f=3.4;是否正确? 答:不正确,编译无法通过 ...

  9. 玩转Django2.0---Django笔记建站基础十一(一)(音乐网站开发)

    第十一章 音乐网站开发 本章以音乐网站项目为例,介绍Django在实际项目开发中的应用,该网站共分为6个功能模块分别是:网站首页.歌曲排行榜.歌曲播放.歌曲点评.歌曲搜索和用户管理. 11.1 网站需 ...

  10. MATLAB2017 下载及安装教程

    全文借鉴于软件安装管家 链接: https://pan.baidu.com/s/1-X1Hg35bDG1G1AX4MnHxnA 提取码: ri88 复制这段内容后打开百度网盘手机App,操作更方便哦 ...