Java中notify()和notifyAll()的使用区别

本文介绍了Java中对象监视器方法notify()和notifyAll()的工作原理和区别。当线程调用wait()后进入等待池,notify()只会唤醒一个线程进入锁池竞争锁,而notifyAll()会唤醒所有线程。仅调用notify()可能导致死锁,而notifyAll()则不会出现这种情况。示例代码展示了notify()可能引发的死锁问题以及notifyAll()如何避免该问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要介绍Javanotify()notifyAll()的区别。用示例代码详细介绍,感兴趣的朋友可以参考一下。

notify()notifyAll()有什么区别?

 

先解释两个概念。

 

等待池:假设一个线程A调用一个对象的wait()方法,它会释放该对象的锁,进入该对象的等待池,等待池中的线程不会争夺该对象的锁。

锁池:只有获得对象的锁,线程才能执行对象的同步代码。一次只有一个线程可以获得对象的锁,其他线程只能在锁池中等待。

 

然后再来说notifynotifyAll的区别

 

如果线程调用了对象的wait()方法,线程就会在对象的等待池中,等待池中的线程不会竞争对象的锁。

当一个线程调用一个对象的notifyAll()方法(唤醒所有等待线程)notify()方法(随机只唤醒一个等待线程)时,被唤醒的线程会进入该对象的锁池,锁池中的线程会争夺该对象的锁。也就是说,一旦调用notify,只有一个线程会从等待池进入锁池,notifyAll会将对象的等待池中的所有线程都移到锁池中,等待锁竞争。

高优先级线程竞争对象锁的可能性很高。如果一个线程不竞争对象锁,它将留在锁池中。只有当线程再次调用wait()方法时,它才会返回等待池。竞争对象锁的线程将继续执行,直到同步代码块完成,并且它将释放对象锁。此时,锁池中的线程将继续竞争对象锁。

综上所述,所谓唤醒线程的另一种解释是将线程从等待池移到锁池。调用notifyAll后,所有线程都将从等待池移动到锁池,然后参与锁竞争。如果竞争成功,它将继续执行。如果不成功,它将留在锁池中,等待锁被释放后再重新参加比赛。而notify只会唤醒一个线程。

有了这些理论基础,就很容易解释下面这个例子,notify可能会导致死锁,但notifyAll不会。

 

测试代码

 

公共类TestNotifyNotifyAll {

私有静态对象obj=new Object()

公共静态void main(String[] args) {

//测试RunnableImplA wait()

线程t1=新线程(runnable impla(obj))

线程t2=新线程(runnable impla(obj))

t1 . start()

T2 . start()

//RunnableImplB notify()

Thread t3=新线程(new RunnableImplB(obj))

T3 . start()

RunnableImplC notifyAll()

//Thread T4=new Thread(new RunnableImplC(obj))

//T4 . start()

}

}

RunnableImplA实现Runnable {

私有对象obj

public runnable impla(Object obj){

this.obj=obj

}

公共无效运行(){

system . out . println(' runnable impla上运行')

同步(对象){

System.out.println('obj以等待runnable impla ')

尝试{

obj . wait()

} catch (InterruptedException e) {

e . printstacktrace()

}

System.out.println('obj继续在RunnableImplA上运行')

}

}

}

RunnableImplB实现Runnable {

私有对象obj

public RunnableImplB(Object obj){

this.obj=obj

}

公共无效运行(){

system . out . println(' run on runnable implb ')

System.out.println('睡眠3.');

尝试{

thread . sleep(3000)

} catch (InterruptedException e) {

e . printstacktrace()

}

同步(对象){

system . out . println(' notify obj on runnable implb ')

obj . notify()

}

}

}

RunnableImplC实现Runnable {

私有对象obj

public runnable implc(Object obj){

this.obj=obj

}

公共无效运行(){

system . out . println(' run on runnable implc ')

System.out.println('睡眠3.');

尝试{

thread . sleep(3000)

} catch (InterruptedException e) {

e . printstacktrace()

}

同步(对象){

system . out . println(' notify all obj on runnable implc ')

obj . notifyall()

}

}

}

结果:仅调用一次obj.notify(),线程一种网络的名称(传输率可达1.54mbps)级(一种通讯线路的名称)t2中的一个始终在等待被唤醒,程序不终止

RunnableImplA上运行

等待RunnableImplA

RunnableImplA上运行

等待RunnableImplA

RunnableImplB上运行

睡眠3.

RunnableImplB上通知对象

目标文件继续在RunnableImplA上运行

t3注掉,启动t4线程。调用obj.notifyAll()方法

公共类TestNotifyNotifyAll {

私有静态对象obj=new Object()

公共静态void main(String[] args) {

//测试RunnableImplA等待()

线程t1=新线程(新runnable impla(obj))

线程t2=新线程(新runnable impla(obj))

t1start()

T2start()

RunnableImplB notify()

//Thread T3=new Thread(new RunnableImplB(obj))

//T3start()

//RunnableImplC notifyAll()

线程t4=新线程(new RunnableImplC(obj))

T4start()

}

}

结果:t1t2线程均可以执行完毕

RunnableImplA上运行

等待RunnableImplA

RunnableImplA上运行

等待RunnableImplA

RunnableImplC上运行

睡眠3.

RunnableImplC上的notifyAll对象

目标文件继续在RunnableImplA上运行

目标文件继续在RunnableImplA上运行

到此这篇关于Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)中通知()notifyAll()的使用区别的文章就介绍到这了,更多相关Java 语言(一种计算机语言,尤用于创建网站)通知()notifyAll()内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

原文地址:Java中notify()和notifyAll()的使用区别_菜鸟教程之家

本文来自网络,不代表菜鸟教程之家立场,转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值