`

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();
	}
}

 

 

 

分享到:
评论

相关推荐

    wait和notifyAll方法的使用示例

    ### 使用wait和notifyAll方法详解 #### 一、引言 在Java多线程编程中,`wait()` 和 `notifyAll()` 方法是非常重要的同步机制,主要用于实现线程间的通信与同步控制。通过合理运用这些方法,可以有效地解决生产者...

    Java 中Object的wait() notify() notifyAll()方法使用

    Java 中Object的wait() notify() notifyAll()方法使用 在Java并发编程中,Object的wait()、notify()和...wait()、notify()和notifyAll()方法是Java并发编程中非常重要的概念,理解它们的使用方法和价值是非常重要的。

    java中几个notify、wait使用实例

    当一个线程执行到`wait()`方法时,它会释放当前持有的锁并进入等待状态,直到其他线程调用同一锁上的`notify()`或`notifyAll()`方法唤醒。`wait()`方法还有两个重载版本:`wait(long timeout)`和`wait(long timeout,...

    Java多线程wait和notify

    `wait()` 方法会让当前持有锁的线程进入等待状态,释放锁,直到其他线程调用 `notify()` 或 `notifyAll()` 唤醒它。`notify()` 则会随机选择一个等待在该对象监视器上的线程并唤醒它,而 `notifyAll()` 则会唤醒所有...

    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。。。三个线程...

    等待机制与锁机制wait notify

    本文将深入探讨`wait`、`notify`以及`notifyAll`这三个关键字的使用及其背后的原理,帮助你理解如何在实际编程中有效地利用它们来解决线程同步问题。 首先,我们需要了解Java中的对象锁。每个Java对象都有一个内置...

    深入理解Wait、Notify和Wait与sleep区别

    1. **wait()**:当一个线程调用对象的`wait()`方法时,它会释放当前对象的锁,并进入等待池,直到其他线程调用同一对象的`notify()`或`notifyAll()`方法唤醒它。唤醒后,线程不会立即恢复执行,而是需要重新获取对象...

    一个理解wait()与notify()的例子

    本文旨在解析一个具体的Java多线程示例代码,以帮助读者更好地理解`wait()`与`notify()`方法的作用及其实现机制。这两个方法是Java中实现线程间通信的重要手段之一,尤其在解决生产者消费者模型、读者写者问题等经典...

    wait,notify等线程知识.pdf

    `wait()` 方法用于使当前线程进入等待状态,直到其他线程调用该对象的 `notify()` 或 `notifyAll()` 方法来唤醒它。当调用 `wait()` 方法时,当前线程会释放锁,并等待其他线程唤醒。`wait()` 方法通常在一个循环中...

    sleep() 方法和wait()方法的区别.docx

    wait() 方法可以通过 notify 或者 notifyAll 或者指定睡眠时间来唤醒当前等待池中的线程。 sleep() 和 wait() 方法的区别 sleep() 和 wait() 方法的最大区别是: 1. sleep() 睡眠时,保持对象锁,仍然占有该锁; ...

    java多线程之wait(),notify(),notifyAll()的详解分析

    Java多线程编程中,`wait()`, `notify()`, 和 `notifyAll()` 是三个非常重要的方法,它们用于线程间通信和同步。这些方法并不是定义在 `Thread` 类中的,而是作为 `Object` 类的一部分,这意味着任何Java对象都可以...

    Thread_comm.rar_comm

    当一个线程调用wait()方法时,它会释放持有锁并进入等待状态,直到其他线程调用同一对象的notify()或notifyAll()方法唤醒它。 3. **条件变量(Condition)**:在Java并发包java.util.concurrent.locks中,条件变量...

    一家三口共用同一账户银行卡,wait();notify();

    在给定的代码示例中,我们看到了一个模拟家庭共享同一银行账户的场景,通过使用Java多线程的wait()和notify()方法来控制不同线程(代表家庭成员)的操作顺序。这里涉及到的关键知识点包括: 1. **Java多线程**:...

    java_thread_demo

    Java提供了wait(), notify()和notifyAll()方法,这些方法需要在synchronized块或方法中调用,用于在线程间交换信息。另外,还有java.util.concurrent包下的BlockingQueue,它可以作为线程间的生产者-消费者模型,...

    java-wait和notify的用法.pdf

    `wait()`方法的作用是使当前持有对象锁的线程暂停执行,进入等待池,释放对象锁,直到其他线程调用同一对象的`notify()`或`notifyAll()`方法来唤醒它。当线程被唤醒后,它并不会立即恢复执行,而是需要再次竞争对象...

    java面试题经典讲解2023年最新题目分析.docx

    10. HashMap什么样的类适合作为键String最为常见,因为String对象不可变,且重写了equals和hashcode方法。...sleep可在任意地方使用,wait notify notifyAll只能在synchronized块\方法中使用。sleep必须捕获异常

    详解Java程序并发的Wait-Notify机制

    在Java中,`wait()`, `notify()`, `notifyAll()`方法是`Object`类的成员,而不是`Thread`类的,这意味着任何对象都可以作为等待和通知的基础。 **1. 状态变量(State Variable)** 状态变量是线程间通信的关键。当...

    06_Thread_java_boardkbl_

    - **wait(), notify()和notifyAll()**:这些方法在Object类中定义,用于线程间通信,必须在同步块或同步方法中使用。 - **生产者-消费者模型**:使用BlockingQueue实现线程间的数据交换,避免死锁。 - **哲学家...

    java_Thread.rar_java thread runable_thread runable

    - `wait()`, `notify()`, `notifyAll()`:这些方法在`Object`类中,用于线程间的协作。一个线程调用`wait()`会释放同步锁并等待,而其他线程可以通过`notify()`或`notifyAll()`唤醒等待的线程。 - `join()`: 使当前...

Global site tag (gtag.js) - Google Analytics