博客
关于我
wait()与notify()
阅读量:428 次
发布时间:2019-03-06

本文共 4037 字,大约阅读时间需要 13 分钟。

一,前言

​ 简单画了一下线程的流程图,只是一个大概。如图所示,线程有多种状态,那么不同状态之间是如何切换的,下面主要总结关于wait()和notify()的使用。

二,wait()

​ wait()和notify()都是定义在Object类中,为什么如此设计。因为synchronized中的这把锁可以是任意对象,所以任意对象都可以调用wait()和notify(),并且只有同一把锁才能对线程进行操作,不同锁之间是不可以相互操作的,所以wait和notify属于Object。请看如下API文档说明。

​ wait()提供三种构造方法,但前两种最为常用,wait()是让线程一直处于等待状态,直到手动唤醒,而wait(long timeout)可以指定等待时间,之后会自动唤醒。

​ 调用wait方法可以让当前线程进入等待唤醒状态,该线程会处于等待唤醒状态直到另一个线程调用了object对象的notify方法或者notifyAll方法。

三,notify()

​ notify()唤醒等待的线程,如果监视器种只有一个等待线程,使用notify()可以唤醒。但是如果有多条线程notify()是随机唤醒其中一条线程,与之对应的就是notifyAll()就是唤醒所有等待的线程,请看下面实例代码。

​ 案例:定义两条线程,分别让其线程等待,及线程唤醒。

​ 1,定义线程。

public class SetTarget implements Runnable{	private Demo demo;	public SetTarget(Demo demo) {		this.demo = demo;	}	@Override	public void run() {		demo.set();	}}
public class GetTarget implements Runnable {	private Demo demo;	public GetTarget(Demo demo) {		this.demo = demo;	}	@Override	public void run() {		demo.get();	}}

​ 2,编写main方法。

public class Demo {	// 定义一个信号量	private volatile int signal;	public static void main(String[] args) {				Demo demo = new Demo();		SetTarget set = new SetTarget(demo);		GetTarget get = new GetTarget(demo);				// 开启线程,		new Thread(get).start();		new Thread(get).start();		new Thread(get).start();		new Thread(get).start();				try {			TimeUnit.SECONDS.sleep(1);		} catch (InterruptedException e) {			e.printStackTrace();		}				new Thread(set).start();	}	// set方法唤醒线程	public synchronized void set() {		signal = 1;		// notify方法会随机叫醒一个处于wait状态的线程		notify(); 		// notifyAll叫醒所有的处于wait线程,争夺到时间片的线程只有一个		//notifyAll();		System.out.println("叫醒线程叫醒之后休眠开始...");		try {			Thread.sleep(3000);		} catch (InterruptedException e) {			e.printStackTrace();		}	}	// get方法使线程进入等待状态	public synchronized int get() {		System.out.println(Thread.currentThread().getName() + " 方法执行了...");		if (signal != 1) {			try {				wait();				System.out.println("叫醒之后");			} catch (InterruptedException e) {				e.printStackTrace();			}		}		System.out.println(Thread.currentThread().getName() + " 方法执行完毕...");		return signal;	}}

​ 3,运行结果。

​ 分析:一共开启了4个线程,当全部进入等待状态时,调用notify()方法唤醒线程,但很明显只唤醒了其中一条线程。右上角显示程序并没有停止,原因就是其他3条线程仍在处于等待状态。

​ 使用notifyAll()唤醒线程:

四,生产者-消费者模式

​ 生产者-消费者模式,生产者生产商品,然后通知消费者进行消费。

​ 1,定义生产者

public class Vendor {	// 定义库存数量	private int count;	// 定义最大库存	private final int MAX_COUNT = 10;	public synchronized void production() {		while (count >= MAX_COUNT) {			try {				System.out.println(Thread.currentThread().getName() + "库存数量达到最大值,停止生产。");				// 此时生产线程全部进入等待状态				wait();			} catch (InterruptedException e) {				e.printStackTrace();			}		}		// 否则生产商品		count++;		System.out.println(Thread.currentThread().getName() + "正在生产商品,当前库存为:" + count);		notifyAll();	}	public synchronized void consumers() {		while (count <= 0) {			try {				System.out.println(Thread.currentThread().getName() + "没有商品了,消费者处于等待状态...");				wait();			} catch (InterruptedException e) {				e.printStackTrace();			}		}		count--;		System.out.println(Thread.currentThread().getName() + "正在消费,当前库存为:" + count);		notifyAll();	}}

​ 2,分别定义两条线程。

public class SetTarget implements Runnable {	private Vendor vendor;	public SetTarget(Vendor vendor) {		this.vendor = vendor;	}	@Override	public void run() {		while(true){			vendor.production();			try {				Thread.sleep(1000);			} catch (InterruptedException e) {				// TODO Auto-generated catch block				e.printStackTrace();			}		}	}}
public class GetTarget implements Runnable {	private Vendor vendor;	public GetTarget(Vendor vendor) {		this.vendor = vendor;	}	@Override	public void run() {		while(true){			vendor.consumers();			try {				Thread.sleep(1000);			} catch (InterruptedException e) {				// TODO Auto-generated catch block				e.printStackTrace();			}		}	}}

​ 3,主方法。

public class Demo {	public static void main(String[] args) {		Vendor vendor = new Vendor();		SetTarget set = new SetTarget(vendor);		GetTarget get = new GetTarget(vendor);				// 开启线程生产商品		new Thread(set).start();		new Thread(set).start();		new Thread(set).start();		new Thread(set).start();				// 开启消费者线程		new Thread(get).start();	}}

​ 4,运行结果。

五,总结

​ 线程之间通信就做这么一个简单的总结,以上内容如有错误,欢迎留言指正。

感谢阅读!

转载地址:http://xbnuz.baihongyu.com/

你可能感兴趣的文章
Mysql学习总结(69)——Mysql EXPLAIN 命令使用总结
查看>>
Mysql学习总结(6)——MySql之ALTER命令用法详细解读
查看>>
Mysql学习总结(70)——MySQL 优化实施方案
查看>>
Mysql学习总结(71)——MySQL 重复记录查询与删除总结
查看>>
Mysql学习总结(73)——MySQL 查询A表存在B表不存在的数据SQL总结
查看>>
Mysql学习总结(77)——温故Mysql数据库开发核心原则与规范
查看>>
Mysql学习总结(78)——MySQL各版本差异整理
查看>>
Mysql学习总结(79)——MySQL常用函数总结
查看>>
Mysql学习总结(7)——MySql索引原理与使用大全
查看>>
Mysql学习总结(80)——统计数据库的总记录数和库中各个表的数据量
查看>>
Mysql学习总结(81)——为什么MySQL不推荐使用uuid或者雪花id作为主键?
查看>>
Mysql学习总结(82)——MySQL逻辑删除与数据库唯一性约束如何解决?
查看>>
Mysql学习总结(83)——常用的几种分布式锁:ZK分布式锁、Redis分布式锁、数据库分布式锁、基于JDK的分布式锁方案对比总结
查看>>
Mysql学习总结(84)—— Mysql的主从复制延迟问题总结
查看>>
Mysql学习总结(85)——开发人员最应该明白的数据库设计原则
查看>>
Mysql学习总结(8)——MySql基本查询、连接查询、子查询、正则表达查询讲解
查看>>
MySQL学习笔记十七:复制特性
查看>>
Mysql学习第一课-mysql的定义及sql语句
查看>>
mysql安装卡在最后一步解决方案(附带万能安装方案)
查看>>
mysql安装和启动命令小结
查看>>