`

Thread_wait、notify、notifyAll的使用方法

 
阅读更多

wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。

这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。
•如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
•如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
•如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。

其中wait方法有三个over load方法:
wait()
wait(long)
wait(long,int)

wait方法通过参数可以指定等待的时长。如果没有指定参数,默认一直等待直到被通知。

以下是一个演示代码,以最简洁的方式说明复杂的问题,简要说明下:

1.NotifyThread是用来模拟3秒钟后通知其他等待状态的线程的线程类;

2.WaitThread是用来模拟等待的线程类;

3.等待的中间对象是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。
没错,这段程序有很多问题,我们一个个来看。首先,这儿要非常注意的几个事实是:
1.任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。
2.无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
3.如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。
4.JVM基于多线程,默认情况下不能保证运行时线程的时序性

基于以上几点事实,我们需要确保让线程拥有对象的控制权。也就是说在waitThread中执行wait方法时,要保证waitThread对flag有控制权;
在notifyThread中执行notify方法时,要保证notifyThread对flag有控制权。

线程取得控制权的方法有三:
1.执行对象的某个同步实例方法。
2.执行对象对应类的同步静态方法。
3.执行对该对象加同步锁的同步块。


我们用第三种方法来做说明:
将以上notify和wait方法包在同步块中

 

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) {
	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);// 推迟3秒钟通知
			} 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();
	}
}

 

 

 

分享到:
评论

相关推荐

    mylty_thread_review

    no2_wait_notify wait-notify-notifyAll的实例 no3_thread_hangup 线程挂起的几种实现方式 no4_join join的实例 no5_thread_stop 停止线程的几种方法 no6_deadlock 模拟死锁 no7_threadlocal ThreadLocal...

    【并发编程】 — 线程间的通信wait、notify、notifyAll

    文章目录1 wait、notify、notifyAll简单介绍1.1 使用方法 + 为什么不是Thread类的方法1.2 什么时候加锁、什么时候释放锁?1.3 notify、notifyAll的区别2 两个比较经典的使用案例2.1 案例1 — ABCABC。。。三个线程...

    sleep()、wait()、yield()和join()方法特点及区别.docx

    1.这两个方法来自不同的类,sleep是Thread类的方法,而wait是Object类的方法; 2.执行sleep方法后不会释放锁,而执行wait方法后会释放锁; 3.wait,notify和notifyAll只能在同步方法或同步代码块中调用,而sleep可以...

    Java并发编程:设计原则与模式(第二版)

    读者将通过使用java.lang.thread类、synchronized和volatile关键字,以及wait、notify和notifyall方法,学习如何初始化、控制和协调并发操作。此外,本书还提供了有关并发编程的全方位的详细内容,例如限制和同步、...

    java中的并发和多线程编程中文版

    读者将通过使用java.lang.thread类、synchronized和volatile关键字,以及wait、notify和notifyall方法,学习如何初始化、控制和协调并发操作。此外,本书还提供了有关并发编程的全方位的详细内容,例如限制和同步、...

    java并发编程:线程基础

    本资源致力于向您介绍 Java 并发编程中的线程基础,涵盖了多线程编程的核心概念、线程...线程间通信: 详解线程间通信的方法,包括 wait、notify 和 notifyAll 方法的使用。讲解如何通过这些方法实现线程的协作和同步。

    100家大公司java笔试题汇总

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。) sleep...

    jstack生成的Thread Dump日志.docx

    只有当别的线程在该对象上调用了 notify()或者notifyAll()方法,"Wait Set"队列中的线程才得到机会去竞争,但是只有一个线程获得对象的Monitor,恢复到运行态。"Wait Set"中的线程在Thread Dump中显示的状态为 in ...

    java笔试题大集合及答案(另附各大公司笔试题)

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 62、同步和...

    Java并发程序设计教程

    4、线程间的协调手段:lock、condition、wait、notify、notifyAll☆☆☆ 5、Lock-free: atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList☆☆☆ 6、关于锁使用的经验介绍 7、并发流程控制手段:...

    java并发编程

    , 这里,读者将通过使用java.lang.thread类、synchronized和volatile关键字,以及wait、notify和notifyall方法,学习如何初始化、控制和协调并发操作。此外,本书还提供了有关并发编程的全方位的详细内容,例如限制...

    java多线程设计模式详解(PDF及源码)

    wait set——线程的休息室 wait方法——把线程放入wait set notify方法——从wait set拿出线程 notifyAll方法——从wait set拿出所有线程 wait、notify、notifyAll是Object类的方法 线程的状态移转 跟线程有关的其他...

    Java多线程机制(讲述java里面与多线程有关的函数)

    Java多线程机制 9.1 Java中的线程 9.2 Thread的子类创建线程 ...9.7 在同步方法中使用wait()、notify 和notifyAll()方法 9.8 挂起、恢复和终止线程 9.9 计时器线程Timer 9.10 线程联合 9.11 守护线程

    java 多线程设计模式 进程详解

    wait()、notify()和notifyAll() wait()和sleep() 线程中断 静态方法(有关同步的细节) 总结 第五章 Java线程编程的例子 数据结构和容器 简单的同步例子 一个网络服务器类 AsyncInputStream类 使用TCP...

    java高并发相关知识点.docx

    Java高并发相关知识点包括: 线程:Java多线程的实现方式,包括继承Thread类和实现Runnable接口。 锁:Java中的锁机制,包括...线程间通信:Java中的线程间通信,包括wait()、notify()、notifyAll()等方法。

    LeetCode判断字符串是否循环-java:Java

    LeetCode判断字符串是否循环 知识点总结 java基础 1、使用迭代器和for each循环查看集合元素时只能获得元素的值,不能改变元素 ...object的方法:wait(notify,notifyall),thread的方法:(sleep、join),结束

    高级开发并发面试题和答案.pdf

    描述一下notify和notifyAll区别; synchronized关键字加在静态方法和实例方法的区别; 用锁的注意点; cas机制可能导致的问题ABA,什么是ABA; 程序开多少线程合适; 实现一下DCL(双重检查锁) stream 和 parallel...

    Java—线程的通信

    文章目录Java—线程的通信概念引入wait()与notify()和notifyAll()生产者和消费者模式 概念 线程通信概念:线程是操作系统中独立的个体,但这些个体如果不经过特殊处理就不能成为一个整体,线程间的通信就成为...

    多线程编程(电子书)

    Java自1995年面世以来得到了广泛得一个运用,但是对多...在Java 5.0之前Java里的多线程编程主要是通过Thread类,Runnable接口,Object对象中的wait()、 notify()、 notifyAll()等方法和synchronized关键词来实现的。

    超级有影响力霸气的Java面试题大全文档

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 17、...

Global site tag (gtag.js) - Google Analytics