/**
* 转载请注明作者longdick http://longdick.iteye.com
*
*/
wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。
这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。
- 如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
- 如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
- 如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
其中wait方法有三个over load方法:
wait()
wait(long)
wait(long,int)
wait方法通过参数可以指定等待的时长。如果没有指定参数,默认一直等待直到被通知。
以下是一个演示代码,以最简洁的方式说明复杂的问题:
简要说明下:
NotifyThread是用来模拟3秒钟后通知其他等待状态的线程的线程类;
WaitThread是用来模拟等待的线程类;
等待的中间对象是flag,一个String对象;
main方法中同时启动一个Notify线程和三个wait线程;
- public class NotifyTest {
- private String flag = "true";
- class NotifyThread extends Thread{
- public NotifyThread(String name) {
- super(name);
- }
- public void run() {
- try {
- sleep(3000);//推迟3秒钟通知
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- flag = "false";
- flag.notify();
- }
- };
- class WaitThread extends Thread {
- public WaitThread(String name) {
- super(name);
- }
- public void run() {
- while (flag!="false") {
- System.out.println(getName() + " begin waiting!");
- long waitTime = System.currentTimeMillis();
- try {
- flag.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- waitTime = System.currentTimeMillis() - waitTime;
- System.out.println("wait time :"+waitTime);
- }
- System.out.println(getName() + " end waiting!");
- }
- }
- public static void main(String[] args) throws InterruptedException {
- System.out.println("Main Thread Run!");
- NotifyTest test = new NotifyTest();
- NotifyThread notifyThread =test.new NotifyThread("notify01");
- WaitThread waitThread01 = test.new WaitThread("waiter01");
- WaitThread waitThread02 = test.new WaitThread("waiter02");
- WaitThread waitThread03 = test.new WaitThread("waiter03");
- notifyThread.start();
- waitThread01.start();
- waitThread02.start();
- waitThread03.start();
- }
- }
OK,如果你拿这段程序去运行下的话, 会发现根本运行不了,what happened?满屏的java.lang.IllegalMonitorStateException。
没错,这段程序有很多问题,我们一个个来看。
首先,这儿要非常注意的几个事实是
- 任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。
- 无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
- 如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。
- JVM基于多线程,默认情况下不能保证运行时线程的时序性
基于以上几点事实,我们需要确保让线程拥有对象的控制权。
也就是说在waitThread中执行wait方法时,要保证waitThread对flag有控制权;
在notifyThread中执行notify方法时,要保证notifyThread对flag有控制权。
线程取得控制权的方法有三:
- 执行对象的某个同步实例方法。
- 执行对象对应类的同步静态方法。
- 执行对该对象加同步锁的同步块。
- synchronized (flag) {
- flag = "false";
- flag.notify();
- }
- synchronized (flag) {
- while (flag!="false") {
- System.out.println(getName() + " begin waiting!");
- long waitTime = System.currentTimeMillis();
- try {
- flag.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- waitTime = System.currentTimeMillis() - waitTime;
- System.out.println("wait time :"+waitTime);
- }
- System.out.println(getName() + " end waiting!");
- }
我们向前进了一步。
问题解决了吗?
好像运行还是报错java.lang.IllegalMonitorStateException。what happened?
这时的异常是由于在针对flag对象同步块中,更改了flag对象的状态所导致的。如下:
flag="false";
flag.notify();
对在同步块中对flag进行了赋值操作,使得flag引用的对象改变,这时候再调用notify方法时,因为没有控制权所以抛出异常。
我们可以改进一下,将flag改成一个JavaBean,然后更改它的属性不会影响到flag的引用。
我们这里改成数组来试试,也可以达到同样的效果:
- private String flag[] = {"true"};
- synchronized (flag) {
- flag[0] = "false";
- flag.notify();
- }
- synchronized (flag) {
- while (flag[0]!="false") {
- System.out.println(getName() + " begin waiting!");
- long waitTime = System.currentTimeMillis();
- try {
- flag.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
这时候再运行,不再报异常,但是线程没有结束是吧,没错,还有线程堵塞,处于wait状态。
原因很简单,我们有三个wait线程,只有一个notify线程,notify线程运行notify方法的时候,是随机通知一个正在等待的线程,所以,现在应该还有两个线程在waiting。
我们只需要将NotifyThread线程类中的flag.notify()方法改成notifyAll()就可以了。notifyAll方法会通知所有正在等待对象控制权的线程。
最终完成版如下:
- public class NotifyTest {
- private String flag[] = { "true" };
- class NotifyThread extends Thread {
- public NotifyThread(String name) {
- super(name);
- }
- public void run() {
- try {
- sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (flag) {
- flag[0] = "false";
- flag.notifyAll();
- }
- }
- };
- class WaitThread extends Thread {
- public WaitThread(String name) {
- super(name);
- }
- public void run() {
- synchronized (flag) {
- while (flag[0] != "false") {
- System.out.println(getName() + " begin waiting!");
- long waitTime = System.currentTimeMillis();
- try {
- flag.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- waitTime = System.currentTimeMillis() - waitTime;
- System.out.println("wait time :" + waitTime);
- }
- System.out.println(getName() + " end waiting!");
- }
- }
- }
- public static void main(String[] args) throws InterruptedException {
- System.out.println("Main Thread Run!");
- NotifyTest test = new NotifyTest();
- NotifyThread notifyThread = test.new NotifyThread("notify01");
- WaitThread waitThread01 = test.new WaitThread("waiter01");
- WaitThread waitThread02 = test.new WaitThread("waiter02");
- WaitThread waitThread03 = test.new WaitThread("waiter03");
- notifyThread.start();
- waitThread01.start();
- waitThread02.start();
- waitThread03.start();
- }
- }
相关推荐
源码—Java多线程5—死锁和wait notify notifyAll
主要介绍了Java多线程中wait、notify、notifyAll使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视。本文对这些关键字的使用进行了描述。 在 Java 中可以用 wait、notify 和 notifyAll 来实现...
Java多线程同步(wait()notify()notifyAll())[文].pdf
本篇文章是对java多线程 wait(),notify(),notifyAll()进行了详细的分析介绍,需要的朋友参考下
绍java多线程之wait(),notify(),notifyAll()
文章目录1 wait、notify、notifyAll简单介绍1.1 使用方法 + 为什么不是Thread类的方法1.2 什么时候加锁、什么时候释放锁?1.3 notify、notifyAll的区别2 两个比较经典的使用案例2.1 案例1 — ABCABC。。。三个线程...
Java多线程机制 9.1 Java中的线程 9.2 Thread的子类创建线程 ...9.7 在同步方法中使用wait()、notify 和notifyAll()方法 9.8 挂起、恢复和终止线程 9.9 计时器线程Timer 9.10 线程联合 9.11 守护线程
主要介绍了Java多线程基础 线程的等待与唤醒,需要的朋友可以参考下
wait set——线程的休息室 wait方法——把线程放入wait set notify方法——从wait set拿出线程 notifyAll方法——从wait set拿出所有线程 wait、notify、notifyAll是Object类的方法 线程的状态移转 跟线程有关的其他...
《JAVA多线程设计模式》PDF 下载 《Java线程 高清晰中文第二版》中文第二版(PDF) 前言 第一章 线程简介 Java术语 线程概述 为什么要使用线程? 总结 第二章 Java线程API 通过Thread类创建线程 使用Runable接口...
多线程情况下最常见的问题之一:数据共享; 当多个线程都要去修改某一个共享数据的时候,需要对数据访问进行同步; 锁:threading.Rlock 条件同步:threading.Condition 队列:Queue 首先一个...
java多线程应用实例,包括wait、notify、notifyAll等的应用方法,经过调试,可以直接运行。
Java自1995年面世以来得到了广泛得一个运用,但是对多...在Java 5.0之前Java里的多线程编程主要是通过Thread类,Runnable接口,Object对象中的wait()、 notify()、 notifyAll()等方法和synchronized关键词来实现的。
本资源致力于向您介绍 Java 并发编程中的线程基础,涵盖了多线程编程的核心概念、线程...线程间通信: 详解线程间通信的方法,包括 wait、notify 和 notifyAll 方法的使用。讲解如何通过这些方法实现线程的协作和同步。
4.线程间通信:lock、condition、wait、notify、notifyAll 5.Lock-free:atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList 6.关于锁的经验介绍 7.并发流程控制手段:CountDownLatch、Barrier 8.定时器:...
Java多线程的等待唤醒机制代码演示 通过代码,完整的还原消费者和生产者的等待唤醒过程 生产者和消费者是一个十分经典的多线程协作模式 **常见方法:** - void wait() 当前线程等待,直到被其他线程唤醒 - void...
wait()、notify()和notifyAll() 虚假唤醒 Condition 定制化通信 多线程锁 并发下的集合类 List Set Map Callable接口 线程创建的方式 callable / runnable FutureTask JUC常用辅助类 CountDownLatch (减少计数器) ...
读者将通过使用java.lang.thread类、synchronized和volatile关键字,以及wait、notify和notifyall方法,学习如何初始化、控制和协调并发操作。此外,本书还提供了有关并发编程的全方位的详细内容,例如限制和同步、...
多线程间通信,其实是多个线程操操作同一个资源,但是操作方式不同。典型实例有生产者和消费者,本文也通过实例来分析线程等待唤醒机制。 1、相关API介绍 public final void notify() 唤醒在此对象监视...