关于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

总结

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

相关文章

  • MyBatis之insert主键自增和自定义主键详解

    MyBatis之insert主键自增和自定义主键详解

    本文介绍了如何使用MyBatis解决插入数据时因主键唯一性约束导致的错误问题,以及如何自定义主键生成规则,文中详细解释了如何在MyBatis中配置自增主键,并提供了测试示例
    2024-12-12
  • Java实现将txt文件转成xls文件的方法

    Java实现将txt文件转成xls文件的方法

    今天小编就为大家分享一篇Java实现将txt文件转成xls文件的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-10-10
  • SpringCloud Gateway中GatewayFilterChain执行流程详解

    SpringCloud Gateway中GatewayFilterChain执行流程详解

    Spring Cloud Gateway旨在为微服务架构提供一种简单有效的、统一的 API 路由管理方式。Spring Cloud Gateway 作为 Spring Cloud 生态系中的网关,它不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全、监控/埋点和限流等
    2022-10-10
  • idea中acitviti使用acitBPM插件出现乱码问题及解决方法

    idea中acitviti使用acitBPM插件出现乱码问题及解决方法

    这篇文章主要介绍了idea中acitviti使用acitBPM插件出现乱码问题及解决方法,通过将File Encodings内容设置为UTF-8,本文通过图文展示,需要的朋友可以参考下
    2021-06-06
  • Spring+Mybatis 实现aop数据库读写分离与多数据库源配置操作

    Spring+Mybatis 实现aop数据库读写分离与多数据库源配置操作

    这篇文章主要介绍了Spring+Mybatis 实现aop数据库读写分离与多数据库源配置操作,需要的朋友可以参考下
    2017-09-09
  • springboot运行时新增/更新外部接口的实现方法

    springboot运行时新增/更新外部接口的实现方法

    这篇文章主要介绍了springboot运行时新增/更新外部接口的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • MyBatis中的properties配置(推荐)

    MyBatis中的properties配置(推荐)

    这篇文章给大家介绍了MyBatis中的properties配置,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-12-12
  • Java生成读取条形码和二维码的简单示例

    Java生成读取条形码和二维码的简单示例

    条形码(barcode)是将宽度不等的多个黑条和空白,按照一定的规则排列,用来表示一组信息的图形标识符,而二维码大家应该都很熟悉了,这篇文章主要给大家介绍了关于Java生成读取条形码和二维码的相关资料,需要的朋友可以参考下
    2021-07-07
  • Spring中的set注入方法

    Spring中的set注入方法

    这篇文章主要介绍了Spring中的set注入方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Java中实现Redis管道技术的代码详解

    Java中实现Redis管道技术的代码详解

    在高并发的应用中,数据访问性能往往是系统性能的关键瓶颈之一,Redis作为一款高性能的内存数据库,广泛应用于缓存、会话存储等场景,然而,在某些需要执行大量Redis命令的场景下,网络往返延迟,Redis提供了管道技术解决这一问题,下面小编给大家详细说说
    2025-04-04

最新评论