一,前言

​ 简单画了一下线程的流程图,只是一个大概。如图所示,线程有多种状态,那么不同状态之间是如何切换的,下面主要总结关于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,运行结果。

五,总结

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

感谢阅读!

最新文章

  1. ubuntu 配置VPN
  2. 查看Android系统是User模式还是Eng模式
  3. 【6_100】Same Tree
  4. User Attributes - Inside Active Directory
  5. HDU 4634 Swipe Bo 状态压缩+BFS最短路
  6. 调用webservice查询手机号码归属地信息
  7. ps扩大、缩小选区
  8. Android手机应用程序开发环境配置(Eclipse+Java+ADT)
  9. C# 关于NULL 可空值类型 ? 和空接操作符??
  10. Frequent values
  11. github恢复
  12. 关于NIOS ii烧写的几种方式(转)
  13. Android开发之漫漫长途 XIII——Fragment最佳实践
  14. chrome总是提示“请停用开发者模式运行的扩展程序”
  15. 利用Delphi编写Socket通信程序
  16. python笔记17-全局变量、局部变量
  17. 深入理解苹果系统(Unicode)字符串的排序方法
  18. nginx 拒绝本地ip访问
  19. 使用 Visual Studio 分析器找出应用程序瓶颈
  20. keal

热门文章

  1. PL/SQL 监听程序当前无法识别连接描述符中请求的服务解决
  2. MySQL之备份和还原
  3. js获取Cookie,获取url参数
  4. Java之Exception
  5. unityshader(属性)
  6. Leetcode之深度优先搜索(DFS)专题-515. 在每个树行中找最大值(Find Largest Value in Each Tree Row)
  7. spring-cloud-kubernetes官方demo运行实战
  8. 通过sql命令建表 和 主外键约束以及其他约束
  9. C# winform语音提示
  10. Enum与最佳単例设计