1. wait方法和notify方法

这两个方法,包括notifyAll方法,都是Object类中的方法。在Java API中,wait方法的定义如下:

public final void wait()
throws InterruptedException
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(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 notify method or the notifyAll method. 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 notify method 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()方法的使用的更多相关文章

  1. Java中wait和sleep方法的区别

    1.两者的区别 这两个方法来自不同的类分别是Thread和Object 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法(锁代码块和方法锁). wait ...

  2. 转 Java中wait和sleep方法的区别

    1.两者的区别 这两个方法来自不同的类分别是Thread和Object 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法(锁代码块和方法锁). wait ...

  3. java中substring的使用方法

    java中substring的使用方法 str=str.substring(int beginIndex);截取掉str从首字母起长度为beginIndex的字符串,将剩余字符串赋值给str: str ...

  4. Java中Set的contains()方法

    Java中Set的contains()方法 -- hashCode与equals方法的约定及重写原则 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashCode() a ...

  5. [java,2017-05-16] java中清空StringBuffer的方法以及耗费时间比较

    java中清空StringBuffer的方法,我能想到的有4种: 1. buffer.setLength(0);  设置长度为0 2. buffer.delete(0, buffer.length() ...

  6. java中BorderLayout的使用方法

    相关设置: 使用BorderLayout布局上下左右中布局5个按键,单击中间的那个按键时就关闭窗口 代码: /**** *java中BorderLayout的使用方法 * 使用BorderLayout ...

  7. 【Java】Java中常用的String方法

    本文转载于:java中常用的String方法 1 length()字符串的长度 String a = "Hello Word!"; System.out.println(a.len ...

  8. Java中Set的contains()方法——hashCode与equals方法的约定及重写原则

    转自:http://blog.csdn.net/renfufei/article/details/14163329 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashC ...

  9. java中equals和hashCode方法随笔二

    前几天看了篇关于java中equals和hashCode方法的解析 1.Object类中的equals方法和hashCode方法. Object类中的equals和hashCode方法简单明了,所有的 ...

随机推荐

  1. 2.06StuModify.aspx(修改姓名,性别,所在班级)

    meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title ...

  2. 使用C#和HtmlAgilityPack解析HTML

    近期,有一个需求,需要解析HTML页面,读取一些需要的数据后,插入本地数据库.我知道可以通过正则表达式实现,然而正则表达式之于我,就像汇编语言之于我,一样.我知道它是干什么的,我也知道它能干什么,但是 ...

  3. Linux设置程序开机启动-tomcat开机启动

    假设我有一个tomcat应用需要开机启动. 前提你的JAVA环境变量已经配置好没有问题,检测方法如图 然后找到tomcat的目录,我的目录是 /home/yuqing_4.0/tomcat_share ...

  4. 理论实践:循序渐进理解AWR细致入微分析性能报告

    1. AWR 概述 Automatic Workload Repository(AWR) 是10g引入的一个重要组件.在里面存贮着近期一段时间内(默认是7天)数据库活动状态的详细信息. AWR 报告是 ...

  5. thinkphp中 volist循环的 mod取值的问题

    <ul> <volist name="data" id="arr" key="k" mod="2"&g ...

  6. Jenkins的持续集成

    持续集成:不需要人工干预,持久化.重复的运行一个任务.将代码自动的更新到最新,然后自动运行. 新建项目之前要再Jenkins的全局工具配置里面把git的路径设置好.[全局工具配置]-->[Git ...

  7. HTML5开发——轻量级JSON存储解决方案Lawnchair.js

    Lawnchair是一个轻量级的移动应用程序数据持久化存储方案,同时也是客户端JSON文档存储方法,优点是短小,语法简洁,扩展性比较好. 现在做HTML5移动应用除了LocalStorage的兼容性比 ...

  8. java 反射 (一)

    原文地址https://www.zhihu.com/question/24304289   首先我们了解一下JVM,什么是JVM,Java的虚拟机,java之所以能跨平台就是因为这个东西,你可以理解成 ...

  9. The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online Solution

    A    Live Love 水. #include<bits/stdc++.h> using namespace std; typedef long long ll; ; const i ...

  10. 学号20155311 2016-2017-2 《Java程序设计》第5周学习总结

    学号20155311 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 由于我的ios系统出了一些问题,所以git idea jdk我都重新在windows系统 ...