关于notify()和notifyAll()方法的用法与区别

 更新时间:2026年04月03日 08:38:48   作者:撞撞~  
本文详细解释了Java中`notify()`和`notifyAll()`的区别,前者唤醒一个等待线程,后者唤醒所有等待线程,并提供了示例代码,展示了`notify()`和`notifyAll()`在实际使用中的效果

一、区别

notify()和notifyAll()都是用来用来唤醒调用wait()方法进入等待锁资源队列的线程,区别在于:

notify()

  • 唤醒正在等待此对象监视器的单个线程。
  • 如果有多个线程在等待,则选择其中一个随机唤醒(由调度器决定),唤醒的线程享有公平竞争资源的权利

notifyAll()

  • 唤醒正在等待此对象监视器的所有线程,唤醒的所有线程公平竞争资源

二、示例

notify()

public class ThreadDemo implements Runnable{
	static Object lock = new Object();

	public static void main(String[] args) {
		Thread thread1 = new Thread(new ThreadDemo(), "Thread-a");
		Thread thread2 = new Thread(new ThreadDemo(), "Thread-b");
		thread1.start();
		thread2.start();
		try {
			TimeUnit.SECONDS.sleep(1); // 睡会,让走到子线程
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		synchronized (lock) {
			System.out.println(Thread.currentThread().getName() + " 获得了锁");
			System.out.println("notify前" + thread1.getName() + "状态是" + thread1.getState());
			System.out.println("notify前" + thread2.getName() + "状态是 " + thread2.getState());
			lock.notify(); // 唤醒一个等待lock锁的线程
		}
		try {
			TimeUnit.MILLISECONDS.sleep(300); // 睡会,让被唤醒的子线程走完
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("notify后" + thread1.getName() + "状态是" + thread1.getState());
		System.out.println("notify后" + thread2.getName() + "状态是" + thread2.getState());
	}

	@Override
	public void run() {
		synchronized (lock) {
			System.out.println(Thread.currentThread().getName() + " 获得了锁");
			try {
				lock.wait(); // 等待被唤醒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + " end");
		}
	}
}

结果:

可以看到,子线程在wait()后释放了锁并进入WAITTINT状态,主线程获得锁后调用notify(),这时候其中一个线程(栗子中是Thread-b,也有可能是a)被唤醒并获取到锁继续执行到TERMINATED,而另一个线程a一直WAITTINT状态

Thread-b 获得了锁
Thread-a 获得了锁
main 获得了锁
notify前Thread-a状态是WAITING
notify前Thread-b状态是 WAITING
Thread-b end
notify后Thread-a状态是WAITING
notify后Thread-b状态是TERMINATED

notifyAll()

上面的栗子如果使用notifyAll(),看下结果

public class ThreadDemo implements Runnable{
	static Object lock = new Object();

	public static void main(String[] args) {
		Thread thread1 = new Thread(new ThreadDemo(), "Thread-a");
		Thread thread2 = new Thread(new ThreadDemo(), "Thread-b");
		thread1.start();
		thread2.start();
		try {
			TimeUnit.SECONDS.sleep(1); // 睡会,让走到子线程
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("哈哈哈哈");
		synchronized (lock) {
			System.out.println(Thread.currentThread().getName() + " 获得了锁");
			System.out.println("notify前" + thread1.getName() + "状态是" + thread1.getState());
			System.out.println("notify前" + thread2.getName() + "状态是 " + thread2.getState());
			lock.notifyAll(); // 唤醒所有等待lock锁的线程
		}
		try {
			TimeUnit.MILLISECONDS.sleep(300); // 睡会,让被唤醒的子线程走完
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("notify后" + thread1.getName() + "状态是" + thread1.getState());
		System.out.println("notify后" + thread2.getName() + "状态是" + thread2.getState());
	}

	@Override
	public void run() {
		synchronized (lock) {
			System.out.println(Thread.currentThread().getName() + " 获得了锁");
			try {
				lock.wait(); // 等待被唤醒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + " end");
		}
	}
}

结果,可以看到所有子线程都被唤醒并再次公平竞争锁直到线程终止

Thread-b 获得了锁
Thread-a 获得了锁
哈哈哈哈
main 获得了锁
notify前Thread-a状态是WAITING
notify前Thread-b状态是 WAITING
Thread-a end
Thread-b end
notify后Thread-a状态是TERMINATED
notify后Thread-b状态是TERMINATED

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • JWT整合Springboot的方法步骤

    JWT整合Springboot的方法步骤

    本文主要介绍了JWT整合Springboot的方法步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • 解决SpringBoot框架因post数据量过大没反应问题(踩坑)

    解决SpringBoot框架因post数据量过大没反应问题(踩坑)

    这篇文章主要介绍了解决SpringBoot框架因post数据量过大没反应问题(踩坑),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • SpringBoot+Vue实现SM4加密传输

    SpringBoot+Vue实现SM4加密传输

    本文主要介绍了SpringBoot+Vue实现SM4加密传输,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-02-02
  • JVM自定义类加载器在代码扩展性实践分享

    JVM自定义类加载器在代码扩展性实践分享

    这篇文章主要介绍了JVM自定义类加载器在代码扩展性实践分享,一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载、验证、准备、解析、初始化 、使用和卸载七个阶段,其中验证、准备、解析三个部分统称为连接
    2022-06-06
  • Spring MVC 中 短信验证码功能的实现方法

    Spring MVC 中 短信验证码功能的实现方法

    短信验证功能在各个网站应用都非常广泛,那么在springmvc中如何实现短信验证码功能呢?今天小编抽时间给大家介绍下Spring MVC 中 短信验证码功能的实现方法,一起看看吧
    2016-09-09
  • JAXB简介_动力节点Java学院整理

    JAXB简介_动力节点Java学院整理

    这篇文章主要为大家详细介绍了JAXB简介的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • 通过java.util.TreeMap源码加强红黑树的理解

    通过java.util.TreeMap源码加强红黑树的理解

    通过分析java.util.TreeMap源码来对经典问题红黑树加强理解和理清思路。
    2017-11-11
  • Java的反射机制之获取class详解

    Java的反射机制之获取class详解

    这篇文章主要介绍了Java的反射机制之获取class详解,Class类表示一个类或接口的元数据,通过它可以获取到类或接口的构造函数、方法、字段、注解等信息,也能够创建对象、调用方法等,需要的朋友可以参考下
    2023-09-09
  • 关于SpringCloud灰度发布的实现

    关于SpringCloud灰度发布的实现

    这篇文章主要介绍了关于SpringCloud灰度发布的实现,灰度发布又称金丝雀发布,是在系统升级的时候能够平滑过渡的一种发布方式,灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度,需要的朋友可以参考下
    2023-08-08
  • 基于Java编写简易的算式测试程序

    基于Java编写简易的算式测试程序

    本文将利用Java语言编写一个简易的算式测试程序,这个程序可以自动生成指定数量的加减乘三则运算题目,感兴趣的小伙伴可以了解一下
    2022-05-05

最新评论