我们常用wait(),notify()和notifyAll()方法来进行线程间通信。线程检查一个条件后就行进入等待状态,例如,在“生产者-消费者”模型中,生产者线程发现缓冲区满了就等待,消费者线程通过消费一个产品使得缓冲区有空闲并通知生产者线程。notify()或notifyAll()的调用给一个或多个线程发出通知,告诉它(它们)条件已经发生改变,并且,一旦通知线程离开同步块,所有等待这个对象锁的线程将竞争这个对象锁,幸运的线程获得锁后就从wait()方法返回并继续执行。让我们把这整个操作分成几步来看看wait()和notify()方法之间的竞争条件(race condition),我们将使用“生产者-消费者”模型以便更容易理解这个场景:
  1. 生产者线程测试条件(缓冲区是否已满)并确定必须等待(发现缓冲区满后)
  2. 消费者线程从缓冲区消费一个产品后设置条件
  3. 消费者线程调用notify()方法,由于生产者线程此时还没有等待,这个消息将被忽略。
  4. 生产者线程调用wait()方法并进入等待状态。

因此,由于这里的竞争条件,我们可能在丢失一个通知,如果我们使用缓冲区或者只有一个产品,生产者线程将永远等待,你的程序也就挂起了。

 
现在我们考虑下这个潜在的竞争条件怎么解决。可以通过使用Java提供的synchronized关键字和锁来解决这个竞争条件。为了调用wait(),notify()和notifyAll()方法,我们必须获取调用这些方法的对象上的锁。由于wait()方法在等待前释放了锁并且在wait()方法返回之前重新获得了锁,我们必须使用这个锁来确保检查条件(缓冲区是否已满)和设置条件(从缓冲区取产品)是原子的,而这可以通过同步块或者同步方法实现。
 
简而言之,我们从同步块或者同步方法中调用wait(),notify()和notifyAll()方法可以避免:
  • IllegalMonitorStateException,如果我们不通过同步环境(synchronized context)调用这几个方法,系统将抛出此异常
  • wait()和notify()之间任何潜在的竞争条件。
 
说明:省略了原文中一些无关紧要的段落。

原文地址:
http://javarevisited.blogspot.com/2011/05/wait-notify-and-notifyall-in-java.html
简单粗暴点:
wait是让使用wait方法的对象等待,暂时先把对象锁给让出来,给其它持有该锁的对象用,其它对象用完后再告知(notify)等待的那个对象可以继续执行了,因此,只有在synchronized块中才有意义(否则,如果大家并不遵循同步机制,那还等谁呢?根本没人排队,也就谈不上等待和唤醒了

(转)为什么wait(),notify()和notifyAll()必须在同步块或同步方法中调用的更多相关文章

  1. 为什么wait(),notify()和notifyAll()必须在同步块或同步方法中调

    我们常用wait(),notify()和notifyAll()方法来进行线程间通信.线程检查一个条件后就行进入等待状态,例如,在"生产者-消费者"模型中,生产者线程发现缓冲区满了就 ...

  2. 解释为什么wait()和notify(), notifyAll()要放在同步块中

    首先,wait()是释放锁的,因此wait()之前要先获得锁,而锁在同步块开始的时候获得,结束时释放,即同步块内为持有锁的阶段. 那为什么要设计同步块呢?或者说没有同步块会怎样呢?

  3. Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  4. object的wait()、notify()、notifyAll()、方法和Condition的await()、signal()方法

    wait().notify()和notifyAll()是 Object类 中的方法 从这三个方法的文字描述可以知道以下几点信息: 1)wait().notify()和notifyAll()方法是本地方 ...

  5. Java并发编程(十三)线程间协作的两种方式:wait、notify、notifyAll和Condition

    在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权.因为生产者如果 ...

  6. 多线程之线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  7. 14 线程间协作的两种方式:wait、notify、notifyAll和Condition

    原文链接:http://www.cnblogs.com/dolphin0520/p/3920385.html 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者- ...

  8. 19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  9. Java并发--线程间协作的两种方式:wait、notify、notifyAll和Condition

    在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界 ...

随机推荐

  1. Python函数之递归函数

    递归函数的定义:在这个函数里再调用这个函数本身 最大递归深度默认是997或者998,python从内存角度做的限制 优点:代码变简单 缺点:占内存 一:推导年龄 问a的值是多少: a 比 b 小2,b ...

  2. SQL语法汇总

    以下默认为mySQL与SQLsever都能使用SQLsever不能使用的另外标出来了 显示数据库SHOW DATABASES;进入其中一个数据库USE students;显示进入数据库中的所有表SHO ...

  3. XML使用与总结

    xml是一种比较方便的数据储存方式,它适用于小数据的存储.最常见的适用地方莫过于各种web.config与app.config了.   一.创建一个简单的xml路径 public static str ...

  4. win10远程桌面出现身份验证错误。要求的函数不受支持

    打开组策略,依次展开“计算机配置”->“管理模板”->“系统”->“凭据分配”,设置名称: “加密 Oracle 修正” 为已启用,并设置保护级别为“易受攻击”

  5. Elasticsearch集群

    详细Elasticsearch安装: https://www.cnblogs.com/littlehb/p/8406378.html 安装之前需先优化内核: https://www.cnblogs.c ...

  6. 经典平衡二叉树(AVL树)

    二叉查找树(BSTree)中进行查找.插入和删除操作的时间复杂度都是O(h),其中h为树的高度.BST的高度直接影响到操作实现的性能,最坏情况下,二叉查找树会退化成一个单链表,比如插入的节点序列本身就 ...

  7. php7安装参数编译

    系统:Centos6.8 软件包:php-7.0.14.tar.gz yum install bzip2 bzip2-devel -y yum install curl curl-devel -y y ...

  8. python函数式编程——返回函数

    1.函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回. 2.闭包 注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还 ...

  9. python 进阶读书笔记2 -- python魔法函数

    #!/usr/bin/env python# -*- coding: utf-8 -*- class student: def __init__(self, name_list): self.stud ...

  10. loadrunner场景报错:Error: CCI compilation error -/tmp/brr_5d65oV/netdir/E/\320\324/Action.c (318): undeclared identifier `LAST'解决思路

    在windows下写的脚本编译通过 但是拿到linux agent场景执行中就会提示如下,同样的脚本在windows agent下没有任何问题 agent连的是linux负载机 通过脚本一行一行排查, ...