【Java】【多线程】两个线程间的通信、wait、notify、notifyAll

原创 2018年04月17日 11:40:47

等待唤醒机制:wait()、notify()

1、什么时候需要通信

  • 多个线程并发执行时, 在默认情况下CPU是随机切换线程的
  • 如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印,轮流执行

2、怎么通信

  • 如果希望线程等待, 就调用wait()
  • 如果希望唤醒等待的线程, 就调用notify();
  • 这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用,this
public class Demo1_Notify {
	/**
	 * @param args
	 * 等待唤醒机制
	 */
	public static void main(String[] args) {
		final Printer p = new Printer();
		
		new Thread() {       //线程1
			public void run() {
				while(true) {
					try {
						p.print1();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {   //线程2
			public void run() {
				while(true) {
					try {
						p.print2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
	}
}

//等待唤醒机制
class Printer {
	private int flag = 1;
	public void print1() throws InterruptedException {							
		synchronized(this) {
			if(flag != 1) {
				this.wait();	//当前线程等待,直到被唤醒
			}
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
			flag = 2;
			this.notify();		//随机唤醒单个等待的线程,此时仍然具有执行权,上面使得线程进入等待
		}
	}
	
	public void print2() throws InterruptedException {
		synchronized(this) {
			if(flag != 2) {
				this.wait();
			}
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 1;
			this.notify();
		}
	}
}

2、多个线程通信的问题

  • notify()方法是随机唤醒一个线程
  • notifyAll()方法是唤醒所有线程
  • JDK5之前无法唤醒指定的一个线程
  • 如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件
public class Demo2_NotifyAll {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final Printer2 p = new Printer2();
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print1();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print2();
					} catch (InterruptedException e) {	
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print3();
					} catch (InterruptedException e) {						
						e.printStackTrace();
					}
				}
			}
		}.start();
	}
}

class Printer2 {
	private int flag = 1;
	public void print1() throws InterruptedException {							
		synchronized(this) {
			while(flag != 1) {
				this.wait();	//当前线程等待
			}
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
			flag = 2;
			//this.notify();	//随机唤醒单个等待的线程
			this.notifyAll();
		}
	}
	
	public void print2() throws InterruptedException {
		synchronized(this) {
			while(flag != 2) {
				this.wait();	//线程2在此等待
			}
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 3;
			//this.notify();
			this.notifyAll();
		}
	}
	
	public void print3() throws InterruptedException {
		synchronized(this) {
			while(flag != 3) {
				this.wait();	//线程3在此等待,if语句是在哪里等待,就在哪里起来
						//while循环是循环判断,每次都会判断标记
			}
			System.out.print("i");
			System.out.print("t");
			System.out.print("h");
			System.out.print("e");
			System.out.print("i");
			System.out.print("m");
			System.out.print("a");
			System.out.print("\r\n");
			flag = 1;
			//this.notify();
			this.notifyAll();
		}
	}
}

三、wait()和notify()的通常用法

Java多线程开发中,我们常用到wait()和notify()方法来实现线程间的协作,简单的说步骤如下: 
1. A线程取得锁,执行wait(),释放锁; 
2. B线程取得锁,完成业务后执行notify(),再释放锁; 
3. B线程释放锁之后,A线程取得锁,继续执行wait()之后的代码;

注意:wait(long timeout):让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的notify()方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。


四、通信需要注意的几点:

1、在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法:this.wait()

2、为什么wait方法和notify方法定义在Object这类中?

因为锁对象可以是任意对象,Object是所有的类的基类,所以wait方法和notify方法需要定义在Object这个类中



版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/love_Aym/article/details/79972168

Java多线程中wait, notify and notifyAll的使用

在Java的Object类中有三个final的方法允许线程之间进行资源对象锁的通信,他们分别是: wait(), notify() and notifyAll()。 调用这些方法的当前线程必须拥有此...
  • luoweifu
  • luoweifu
  • 2015-06-27 22:36:37
  • 15637

Java多线程-wait(), notify(), notifyAll()、yield()、sleep()、join()、interrupt()原理及使用

参考:http://www.cnblogs.com/skywang12345/p/java_threads_category.html 一、线程等待与唤醒 1、wait(), notify(), ...
  • Love_JavaProgram
  • Love_JavaProgram
  • 2016-01-08 19:54:20
  • 1646

Java wait()和await() notify()和signal() notifyAll()和signalAll()了解和区别

Java wait()和await() notify()和signal() notifyAll()和signalAll()了解和区别
  • codingtu
  • codingtu
  • 2017-11-03 07:35:20
  • 245

Java并发编程系列之八:wait()、notify()和notifyAll()

代码一个线程修改一个对象的值,而另一个线程则感知到了变化,然后进行相应的操作,这就是wait()、notify()和notifyAll()方法的本质。具体体现到方法上则是这样的:一个线程A调用了对象o...
  • u011116672
  • u011116672
  • 2016-04-02 18:47:20
  • 4506

wait(),notify(),notifyAll()及sleep() 和wait()的区别

在多线程的情况下,由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。 ...
  • zhx1019
  • zhx1019
  • 2014-10-19 15:52:03
  • 1321

【Java并发编程】之十:使用wait/notify/notifyAll实现线程间通信的几点重要说明

在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调...
  • mmc_maodun
  • mmc_maodun
  • 2013-12-09 22:09:26
  • 20522

java notify()和notifyall()的区别&wait()方法的使用

剖析了notify()和notifyAll()方法的区别。
  • leixingbang1989
  • leixingbang1989
  • 2015-12-30 15:22:32
  • 1106

源码—Java多线程5—死锁和wait notify notifyAll

  • 2011年10月14日 10:09
  • 2KB
  • 下载

JAVA多线程中synchronized,wait和notify的关系

synchronized是和一个锁对象关联的,synchronized限制static方法的时候, 锁对象为这个类的class变量,相当于XXXClass.class. synchronized限...
  • kkdelta
  • kkdelta
  • 2012-07-24 13:50:19
  • 15577

Java Object对象中的wait,notify,notifyAll通俗理解

wait,notify,notifyAll 是定义在Object类的实例方法,用于控制线程状态。三个方法都必须在synchronized 同步关键字所限定的作用域中调用,否则会报错java.lang....
  • vk5176891
  • vk5176891
  • 2016-12-30 18:33:48
  • 2379
收藏助手
不良信息举报
您举报文章:【Java】【多线程】两个线程间的通信、wait、notify、notifyAll
举报原因:
原因补充:

(最多只允许输入30个字)