一,前言

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

五,总结

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

感谢阅读!

wait()与notify()的更多相关文章

  1. Thread Object wait() notify()基本

    package com.thread.test.thread; import java.util.ArrayDeque; import java.util.Queue; import java.uti ...

  2. 如何在 Java 中正确使用 wait, notify 和 notifyAll(转)

    wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视.本文对这些关键字的使用进行了描述. 在 Java 中可以用 wait ...

  3. java多线程wait notify join

    wait notify 几个注意点: wait 与 notify/notifyAll 方法必须在同步代码块中使用,即要先对调用对象加锁. 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进 ...

  4. 【Java并发系列02】Object的wait()、notify()、notifyAll()方法使用

    一.前言 对于并发编程而言,除了Thread以外,对Object对象的wati和notify对象也应该深入了解其用法,虽然知识点不多. 二.线程安全基本知识 首先应该记住以下基本点,先背下来也无妨: ...

  5. 【多线程】java多线程 测试例子 详解wait() sleep() notify() start() join()方法 等

    java实现多线程,有两种方法: 1>实现多线程,继承Thread,资源不能共享 2>实现多线程  实现Runnable接口,可以实现资源共享 *wait()方法 在哪个线程中调用 则当前 ...

  6. #研发中间件介绍#异步消息可靠推送Notify

    郑昀 基于朱传志的设计文档 最后更新于2014/11/11 关键词:异步消息.订阅者集群.可伸缩.Push模式.Pull模式 本文档适用人员:研发   电商系统为什么需要 NotifyServer? ...

  7. 线程同步以及 yield() wait()和notify()、notifyAll()

    1.yield() 该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会. 2.wait()和notify().notifyAll() 这 ...

  8. java 多线程之wait(),notify,notifyAll(),yield()

    wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对像都有wait(),notify(),notifyAll()的功能.因为都个对像都 ...

  9. wait、notify、sleep、interrupt对比分析

    对比分析Java中的各个线程相关的wait().notify().sleep().interrupt()方法 方法简述 Thread类 sleep:暂停当前正在执行的线程:(类方法) yield:暂停 ...

  10. java中的wait(),notify(),notifyAll(),synchronized方法

    wait(),notify(),notifyAll()三个方法不是Thread的方法,而是Object的方法.意味着所有对象都有这三个方法,因为每个对象都有锁,所以自然也都有操作锁的方法了.这三个方法 ...

随机推荐

  1. 分享:个人APP(非企业资质)的微信登录方案

    目前微信开放平台个人主体类APP不支持开通微信登录,那么个人开发者如何解决微信登录的问题呢?目前有一种替代方案是用微信小程序作为媒介来达到微信登录的目的. 微信小程序的登录无需企业资质,同时登录后返回 ...

  2. vuex详解vue简单使用

    vue概念:vuex 是 Vue 配套的 公共数据管理工具,它可以把一些共享的数据,保存到 vuex 中,方便 整个程序中的任何组件直接获取或修改我们的公共数据: 配置vuex的步骤: 1.运行cnp ...

  3. windows下 ionic 打包app --以安卓版本为例

    环境安装 1.nodejs 安装版本5.7,尽量不要安装太新的版本,因为可能会出现兼容性问题,一开始本人安装的是6.+的版本,后来出现问题的,马上换回5.7的,问题就不会出现了. 安装教程网上教程很多 ...

  4. unity_UGUI养成之路01

    1.UGUI_UI之音量设计  2.控制音量音效的开关 实现开和关的互斥点击 实现开与关画面的显示 注意,上图并未选择分组.具体原因博主尚不清楚如果有知道的可以告知一二,谢谢各位!!! 代码: usi ...

  5. Leetcode之深度优先搜索(DFS)专题-1123. 最深叶节点的最近公共祖先(Lowest Common Ancestor of Deepest Leaves)

    Leetcode之深度优先搜索(DFS)专题-1123. 最深叶节点的最近公共祖先(Lowest Common Ancestor of Deepest Leaves) 深度优先搜索的解题详细介绍,点击 ...

  6. 2019 HZNU Winter Training Day 14 Comprehensive Training

    A - Choosing Capital for Treeland CodeForces - 219D 题意:有一颗单向边的树,要选取一个结点作为首都.要求是这个结点到其它结点,总共需要翻转的路径数量 ...

  7. codeforces 811 E. Vladik and Entertaining Flags(线段树+并查集)

    题目链接:http://codeforces.com/contest/811/problem/E 题意:给定一个行数为10 列数10w的矩阵,每个方块是一个整数, 给定l和r 求范围内的联通块数量 所 ...

  8. Windows CVE-2019-0708 远程桌面代码执行漏洞复现

    Windows CVE-2019-0708 远程桌面代码执行漏洞复现 一.漏洞说明 2019年5月15日微软发布安全补丁修复了CVE编号为CVE-2019-0708的Windows远程桌面服务(RDP ...

  9. 从原理层面掌握@InitBinder的使用【享学Spring MVC】

    每篇一句 大魔王张怡宁:女儿,这堆金牌你拿去玩吧,但我的银牌不能给你玩.你要想玩银牌就去找你王浩叔叔吧,他那银牌多 前言 为了讲述好Spring MVC最为复杂的数据绑定这块,我前面可谓是做足了功课, ...

  10. Linux-配置YUM仓库

    范例:配置Yum仓库 Yum软件仓库的作用是为了进一步简化RPM管理软件的难度以及自动分析所需软件包及其依赖关系的技术.可以把Yum想象成是一个硕大的软件仓库,里面保存有几乎所有常用的工具,而且只需要 ...