Java中wait()和notify()方法的使用
1. wait方法和notify方法
这两个方法,包括notifyAll方法,都是Object类中的方法。在Java API中,wait方法的定义如下:
public final void wait()
throws InterruptedExceptionCauses the current thread to wait until another thread invokes thenotify()method or thenotifyAll()method for this object. In other words, this method behaves exactly as if it simply performs the callwait(0).The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the
notifymethod or thenotifyAllmethod. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}This method should only be called by a thread that is the owner of this object's monitor. See the
notifymethod for a description of the ways in which a thread can become the owner of a monitor.
在 Java 中可以用 wait、notify 和 notifyAll 来实现线程间的通信。线程在运行的时候,如果发现某些条件没有被满足,可以调用wait方法暂停自己的执行,并且放弃已经获得的锁,然后进入等待状态。当该线程被其他线程唤醒并获得锁后,可以沿着之前暂停的地方继续向后执行,而不是再次从同步代码块开始的地方开始执行。但是需要注意的一点是,对线程等待的条件的判断要使用while而不是if来进行判断。这样在线程被唤醒后,会再次判断条件是否正真满足。
想象一下一个生产者,多个消费者的场景。一个消费者Consumer1了最后一个元素,并且唤醒了其他线程,如果被唤醒的正好是Consumer2,那么此时是没有元素可以消费的。如果用的是if判断,那么被唤醒后就不会再次进行条件的判断,而是直接向下执行导致运行错误。我们的代码如下:
notify方法会唤醒等待一个对象锁的线程,但是具体唤醒哪个是不确定的。
2. 实现生产者消费者
如下使用if来判断会导致程序出错

一定要使用while来进行判断线程的等待条件而不是使用if
package thread.learn; import java.util.LinkedList;
import java.util.Queue;
import java.util.Random; /**
* Created by liujinhong on 2017/4/2.
* 生产者消费者问题是一个很经典的问题,值得好好研究一下
* java的wait和notify方法在使用时也是要非常注意的
*/
public class ProducerConsumer {
public static class Producer extends Thread {
Queue<Integer> queue;
int maxsize; Producer(Queue<Integer> queue, int maxsize, String name) {
this.queue = queue;
this.maxsize = maxsize;
this.setName(name);
}
@Override
public void run() {
while (true) {
synchronized (queue) {
try{
Thread.sleep(500);
} catch (Exception e) {} System.out.println(this.getName() + "获得队列的锁");
//条件的判断一定要使用while而不是if
if (queue.size() == maxsize) {
System.out.println("队列已满,生产者" + this.getName() + "等待");
try {
queue.wait();
} catch (Exception e) {}
}
int num = (int)(Math.random()*100);
queue.offer(num); System.out.println(this.getName() + "生产一个元素:" + num);
queue.notifyAll(); System.out.println(this.getName() + "退出一次生产过程!");
}
}
}
} public static class Consumer extends Thread {
Queue<Integer> queue;
int maxsize; Consumer(Queue<Integer> queue, int maxsize, String name) {
this.queue = queue;
this.maxsize = maxsize;
this.setName(name);
} @Override
public void run() {
while (true) {
synchronized (queue) {
try{
Thread.sleep(500);
} catch (Exception e) {} System.out.println(this.getName() + "获得队列的锁");
//条件的判断一定要使用while而不是if
if (queue.isEmpty()) {
System.out.println("队列为空,消费者" + this.getName() + "等待");
try{
queue.wait();
} catch (Exception e) {}
}
int num = queue.poll();
System.out.println(this.getName() + "消费一个元素:"+num);
queue.notifyAll(); System.out.println(this.getName() + "退出一次消费过程!");
}
}
}
} public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
int maxsize = 2; Producer producer = new Producer(queue, maxsize, "Producer");
Consumer consumer1 = new Consumer(queue, maxsize,"Consumer1");
Consumer consumer2 = new Consumer(queue, maxsize,"Consumer2");
Consumer consumer3 = new Consumer(queue, maxsize,"Consumer3"); producer.start();
consumer1.start();
consumer2.start();
consumer3.start();
}
}
Java中wait()和notify()方法的使用的更多相关文章
- Java中wait和sleep方法的区别
1.两者的区别 这两个方法来自不同的类分别是Thread和Object 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法(锁代码块和方法锁). wait ...
- 转 Java中wait和sleep方法的区别
1.两者的区别 这两个方法来自不同的类分别是Thread和Object 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法(锁代码块和方法锁). wait ...
- java中substring的使用方法
java中substring的使用方法 str=str.substring(int beginIndex);截取掉str从首字母起长度为beginIndex的字符串,将剩余字符串赋值给str: str ...
- Java中Set的contains()方法
Java中Set的contains()方法 -- hashCode与equals方法的约定及重写原则 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashCode() a ...
- [java,2017-05-16] java中清空StringBuffer的方法以及耗费时间比较
java中清空StringBuffer的方法,我能想到的有4种: 1. buffer.setLength(0); 设置长度为0 2. buffer.delete(0, buffer.length() ...
- java中BorderLayout的使用方法
相关设置: 使用BorderLayout布局上下左右中布局5个按键,单击中间的那个按键时就关闭窗口 代码: /**** *java中BorderLayout的使用方法 * 使用BorderLayout ...
- 【Java】Java中常用的String方法
本文转载于:java中常用的String方法 1 length()字符串的长度 String a = "Hello Word!"; System.out.println(a.len ...
- Java中Set的contains()方法——hashCode与equals方法的约定及重写原则
转自:http://blog.csdn.net/renfufei/article/details/14163329 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashC ...
- java中equals和hashCode方法随笔二
前几天看了篇关于java中equals和hashCode方法的解析 1.Object类中的equals方法和hashCode方法. Object类中的equals和hashCode方法简单明了,所有的 ...
随机推荐
- Docker企业级仓库Harbor的安装配置与使用
Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全.标识和管理等,扩展了开源Docker Distribution.作为一个企业级 ...
- ubuntu16.04下安装opencv-nonfree
在写计算机视觉与导航技术的课程作业,是关于sift和surf特征的提取及匹配.因为opencv中都有直接的函数可以调用. 关于SIFT和SURF的特征在opencv的nonfree模块中,从字面意思就 ...
- JavaCSV之写CSV文件
与JavaCSV读CSV文件相对应,JavaCSV也可以用来写数据到CSV文件中. 1.准备工作 (1)第三方包库下载地址:https://sourceforge.net/projects/javac ...
- 使用DBMS_SUPPORT包
DBMS_SUPPORT包从Oracle7.2引入,主要功能用以提供更完整的用户session跟踪信息,这个包可以通过运行 dbmssupp.sql 和 prvtsupp.plb 两个脚本来创建.该脚 ...
- 配置oem
[oracle@kaifai ~]$ export ORACLE_SID=dbking[oracle@kaifai ~]$ export ORACLE_SID=kaifai[oracle@kaifai ...
- python及numpy,pandas易混淆的点
https://blog.csdn.net/happyhorizion/article/details/77894035 初接触python觉得及其友好(类似matlab),尤其是一些令人拍案叫绝不可 ...
- Spring源码解析(五)循环依赖问题
引言 循环依赖就是多个类之间互相依赖,比如A依赖B,B也依赖A,如果日常开发中我们用new的方式创建对象,这种循环依赖就会导致不断的在创建对象,导致内存溢出. Spring是怎么解决循环依赖的问题的? ...
- 翻译:Addressing tiles: same tile bounds with different indexes
原文链接:http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/ Addressing tiles: same ...
- Selenium之firefox浏览器的启动问题及解决
启动firefox报错如下: rg.openqa.selenium.firefox.NotConnectedException: Unable to connect to host 127.0.0.1 ...
- java多线程(六)
使用Runnable接口创建线程 Runnable接口 只有一个run()方法 Thread类实现了Runable接口 便于多个线程共享资源 Java不支持多继承,如果已经继承了某个基类,便要实现Ru ...