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方法简单明了,所有的 ...
随机推荐
- yii2GridView的简单使用
GridView::widget([ 'dataProvider' => $dataProvider,// 你传过来的ActiveDataProvider // 'filterModel' =& ...
- EF的使用(DbContext对象的共用问题)
1.问题的引入 对于某一个数据库的EF操作对象,当执行某一次请求的时候,可能会多次操作数据库,也就是可能创建很多MyDbContext(继承自DbContext对象,EF上下文对象) 2.代码创建 当 ...
- Only a type can be imported. classname resolves to a package的解决
Only a type can be imported. l1.l2.MyClass resolves to a package ==========这里是解决方案=============== 把生 ...
- python基础之函数式编程、匿名函数、内置函数
一 函数式编程 不修改外部状态. 模仿数学里得函数进行编程. 用函数编程写出得代码相当精简. 可读性比较差. 例子: y=2*x+1 x=1 def test(x): return 2*x+1 tes ...
- 深入理解Docker容器执行引擎runC
1 简介 根据官方的定义:runC是一个根据OCI标准创建并运行容器的CLI tool. Docker就是基于runC创建的,简单地说,runC就是docker中最为核心的部分,容器的创建,运行,销毁 ...
- JDK安装(linux系统)
安装好centos6.8以后,输入命令: 如果显示如下: 证明系统自带了JDK,需要手动删除. 然后搜索: 备注: 查询一个包是否被安装 # rpm -q < rpm package name& ...
- java爬取网页内容 简单例子(2)——附jsoup的select用法详解
[背景] 在上一篇博文java爬取网页内容 简单例子(1)——使用正则表达式 里面,介绍了如何使用正则表达式去解析网页的内容,虽然该正则表达式比较通用,但繁琐,代码量多,现实中想要想出一条简单的正则表 ...
- SWIG和PInvoke学习(1)
1. 简介 SWIG是个帮助使用C或者C++编写的软件能与其它各种高级编程语言进行嵌入联接的开发工具. SWIG能应用于各种不同类型的语言包括常用脚本编译语言例如Perl, PHP, Python, ...
- adb shell top 命令
原文地址https://blog.csdn.net/kittyboy0001/article/details/38562515 原文地址https://blog.csdn.net/u010503912 ...
- python中的切片
python中提供了一种很方便的方法来完成取出指定范围内的元素,这种方法就是切片(Slice). 以下为切片的例子: In [1]: L = ['Michael', 'Sarah', 'Tracy', ...