Java中notify和notifyAll的区别 - 何时以及如何使用
Java notify vs notifyAll
notify和notifyAll方法之间有什么区别是棘手的Java问题之一!
Condition 是个什么玩意?
提几个问题,从问题中去了解去学习:
- 他们之间有啥区别?
- 如果我使用notify(),将通知哪个线程?
- 我怎么知道有多少线程在等待,所以我可以使用notifyAll()?
- 如何调用notify()?
- 什么是这些线程等待被通知等?
我给点建议:建议使用jdk8里的lock包
java.util.concurrent.locks下的Condition 他可以支持唤醒指定的线程。
- 他只是一个接口 具体实现类是在
AbstractQueuedSynchronizer 也就是AQS框架里的 你可以自己继承他 或者使用 ReentrantLock里的newConditon()方法来获取
解决下问题:
- Java中notify和notifyAll的区别
- Java提供了两个方法notify和notifyAll来唤醒在某些条件下等待的线程,你可以使用它们中的任何一个,但是Java中的notify和notifyAll之间存在细微差别,这使得它成为Java中流行的多线程面试问题之一。当你调用notify时,只有一个等待线程会被唤醒而且它不能保证哪个线程会被唤醒,这取决于线程调度器。虽然如果你调用notifyAll方法,那么等待该锁的所有线程都会被唤醒,但是在执行剩余的代码之前,所有被唤醒的线程都将争夺锁定,这就是为什么在循环上调用wait,因为如果多个线程被唤醒,那么线程是将获得锁定将首先执行,它可能会重置等待条件,这将迫使后续线程等待。因此,notify和notifyAll之间的关键区别在于notify()只会唤醒一个线程,而notifyAll方法将唤醒所有线程。
- 何时在Java中使用notify和notifyAll
- 如果所有线程都在等待相同的条件,并且一次只有一个线程可以从条件变为true,则可以使用notify over notifyAll。
- 在这种情况下,notify是优于notifyAll 因为唤醒所有这些因为我们知道只有一个线程会受益而所有其他线程将再次等待,所以调用notifyAll方法只是浪费CPU。
- 虽然这看起来很合理,但仍有一个警告,即无意中的接收者吞下了关键通知。通过使用notifyAll,我们确保所有收件人都会收到通知
- Java中通知和notifyAll方法的示例(后序demo示例代码 )
- 我已经汇总了一个示例来说明当我们在Java中调用notifyAll方法时如何通知所有线程,并且当我们在Java中调用notify方法时,只有一个Thread会被唤醒。
- 在这个例子中,如果boolean变量go为false,则三个线程将等待,记住boolean go是一个volatile变量,以便所有线程都能看到它的更新值。
- 最初三个线程WT1,WT2,WT3将等待,因为变量go为假,而一个线程NT1将变为真,并通过调用notifyAll方法通知所有线程,或通过调用notify()方法通知一个线程。在notify()调用的情况下,无法保证哪个线程会被唤醒,您可以通过多次运行此Java程序来查看它。
- 在notifyAll的情况下,所有线程都将被唤醒,但是它们将竞争监视器或锁定,并且将首先获得锁定的线程将完成其执行并且重置为false将迫使其他两个线程仍在等待。在该程序结束时,将有两个线程在等待,两个线程包括通知线程完成。程序不会终止,因为其他两个线程仍在等待,并且它们不是守护程序线程。
- 实例代码如下:以下是如何在Java中使用notify和notifyAll方法的完整代码示例。在解释了何时使用notify vs notifyAll方法,这个例子将阐明在Java中调用notify和notifyAll方法的效果。go!
import java.util.logging.Level;
import java.util.logging.Logger;/*** Java程序演示如何在Java和Java中使用notify和notifyAll方法*如何通知和notifyAll方法通知线程,哪个线程被唤醒等。*/
public class NotificationTest {private volatile boolean go = false;public static void main(String args[]) throws InterruptedException {final NotificationTest test = new NotificationTest();Runnable waitTask = new Runnable(){@Overridepublic void run(){try {test.shouldGo();} catch (InterruptedException ex) {Logger.getLogger(NotificationTest.class.getName()).log(Level.SEVERE, null, ex);}System.out.println(Thread.currentThread() + " finished Execution");}};Runnable notifyTask = new Runnable(){@Overridepublic void run(){test.go();System.out.println(Thread.currentThread() + " finished Execution");}};Thread t1 = new Thread(waitTask, "WT1"); //will waitThread t2 = new Thread(waitTask, "WT2"); //will waitThread t3 = new Thread(waitTask, "WT3"); //will waitThread t4 = new Thread(notifyTask,"NT1"); //will notify//starting all waiting threadt1.start();t2.start();t3.start();//pause to ensure all waiting thread started successfullyThread.sleep(200);//starting notifying threadt4.start();}/** wait and notify can only be called from synchronized method or bock*/private synchronized void shouldGo() throws InterruptedException {while(go != true){System.out.println(Thread.currentThread()+ " is going to wait on this object");wait(); //release lock and reacquires on wakeupSystem.out.println(Thread.currentThread() + " is woken up");}go = false; //resetting condition}/** both shouldGo() and go() are locked on current object referenced by "this" keyword*/private synchronized void go() {while (go == false){System.out.println(Thread.currentThread()+ " is going to notify all or one thread waiting on this object");go = true; //making condition true for waiting thread//notify(); // only one out of three waiting thread WT1, WT2,WT3 will woke upnotifyAll(); // all waiting thread WT1, WT2,WT3 will woke up}}}
使用notify时的输出
Thread[WT1,5,main] is going to wait on this object
Thread[WT3,5,main] is going to wait on this object
Thread[WT2,5,main] is going to wait on this object
Thread[NT1,5,main] is going to notify all or one thread waiting on this object
Thread[WT1,5,main] is woken up
Thread[NT1,5,main] finished Execution
Thread[WT1,5,main] finished Execution
使用notifyAll时的输出
Thread[WT1,5,main] is going to wait on this object
Thread[WT3,5,main] is going to wait on this object
Thread[WT2,5,main] is going to wait on this object
Thread[NT1,5,main] is going to notify all or one thread waiting on this object
Thread[WT2,5,main] is woken up
Thread[NT1,5,main] finished Execution
Thread[WT3,5,main] is woken up
Thread[WT3,5,main] is going to wait on this object
Thread[WT2,5,main] finished Execution
Thread[WT1,5,main] is woken up
Thread[WT1,5,main] is going to wait on this object
强烈建议运行这个Java程序并理解它产生的输出并尝试理解它。除了死锁,竞争条件和线程安全之外,线程间通信是Java中并发编程的基础之一。
总结:
1)如果我使用notify(),将通知哪个线程?
无法保证,ThreadScheduler将从等待该监视器上的线程的池中选择一个随机线程。保证只有一个线程会被通知:(随机性)
2) 我怎么知道有多少线程在等待,所以我可以使用notifyAll()?
它取决于程序逻辑,在编码时需要考虑一段代码是否可以由多个线程运行。理解线程间通信的一个很好的例子是在Java中实现生产者 - 消费者模式。
3) 如何调用notify()?
Wait()和notify()方法只能从synchronized方法或块中调用,需要在其他线程正在等待的对象上调用notify方法。
4) 什么是这些线程等待被通知等?
线程等待某些条件,例如在生产者 - 消费者问题中,如果共享队列已满,则生产者线程等待,如果共享队列为空,则生成者线程等待。由于多个线程正在使用共享资源,因此它们使用wait和notify方法相互通信。
这就是Java中的notify和notifyAll方法之间的区别以及何时在Java中使用notify vs notifyAll。现在,应该能够理解并使用notify和notifyAll方法在Java程序中进行线程间通信。
补充下建议里的:lock包下的condition (demo里 是典型的生产者消费者模式》》》 使用的是condition来实现)
final Lock lock = new ReentrantLock();//定义2组condition 对应生产者消费者final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100];int putptr, takeptr, count;//在put的时候 当数组已经满了的情况下 我让线程等待 不在容纳数据 当消费者已经消费了 触发了、、//notfull.signal() 这时候通知生产者 我这变已经消费了 你那边可以试试了哈。 public void put(Object x) throws InterruptedException {lock.lock();try {while (count == items.length)notFull.await();items[putptr] = x;if (++putptr == items.length) putptr = 0;++count;notEmpty.signal();} finally {lock.unlock();}}
//同上 相反的理解就是了。。。public Object take() throws InterruptedException {lock.lock();try {while (count == 0)notEmpty.await();Object x = items[takeptr];if (++takeptr == items.length) takeptr = 0;--count;notFull.signal();return x;} finally {lock.unlock();}}
Condition
因素出Object
监视器方法(wait
,notify
和notifyAll
)为不同的对象,以得到具有多个等待集的每个对象,通过将它们与使用任意的相结合的效果Lock
的实施方式。如果Lock
替换synchronized
方法和语句Condition
的使用,则替换Object监视方法的使用。条件(也称为条件队列或 条件变量)为一个线程提供暂停执行(“等待”)的手段,直到另一个线程通知某个状态条件现在可能为真。由于对此共享状态信息的访问发生在不同的线程中,因此必须对其进行保护,因此某种形式的锁定与该条件相关联。等待条件提供的关键属性是它以原子方式释放关联的锁并挂起当前线程,就像它一样
Object.wait
。一个
Condition
实例本质上绑定到一个锁。要获取Condition
特定Lock
实例的实例,请使用其newCondition()
方法。举个例子,假设我们有一个支持
put
和take
方法的有界缓冲区 。如果take
在空缓冲区上尝试a ,则线程将阻塞直到某个项可用; 如果put
在完整缓冲区上尝试a,则线程将阻塞,直到空间可用。我们希望 在单独的等待集中保持等待put
线程和take
线程,以便我们可以使用仅在缓冲区中的项或空间可用时通知单个线程的优化。
也就是说 可以创建多个condition 每组condition 对应你的具体的线程操作 当你
notFull.signalAll();的时候 你唤醒的也只是你这组condition里的等待线程 对于不在这组里的notEmpty是没有任何影响的
现在 你是不是可以随心所欲的唤醒你想唤醒的线程了? 都看到这了 还不给个赞吗
Java中notify和notifyAll的区别 - 何时以及如何使用相关推荐
- Java中notify() 和 notifyAll()的区别
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池,等待池中的线程不会去竞争该对象的锁. 锁池:只有获取了对象的锁,线程才能执行对象的 sync ...
- Java 中 notify 和 notifyAll 有什么区别?
notify() 方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有 用武之地.而 notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程 能继续运行.
- Java多线程——notify()与notifyAll()的区别
notify(): 唤醒在此对象监视器上等待的单个线程.如果所有线程都在此对象上等待,则会选择唤醒其中一个线程.选择是任意性的,并在对实现做出决定时发生.线程通过调用其中一个 wait 方法,在对象的 ...
- Java之notify和notifyAll区别
在Java中notify()和notifyAll()方法都是Object对象用于通知处在等待该对象的线程的方法. 两者的最大区别在于: notifyAll方法 使所有原来在该对象上等待被notify的 ...
- java notify什么意思_Java notify和notifyAll的区别和相同
经常在往上逛,关于在java中notify和notifyAll,经常有人有以下的说法: notify只会通知一个在等待的对象,而notifyAll会通知所有在等待的对象,并且所有对象都会继续运行 并且 ...
- java中wait和sleep的区别
文章目录 Wait和sleep的区别 唤醒wait和sleep java中wait和sleep的区别 在本篇文章中,我们将会讨论一下java中wait()和sleep()方法的区别.并讨论一下怎么使用 ...
- Notify与notifyall的区别
Notify与notifyall的区别 notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争. notify则文 ...
- notify 和 notifyAll的区别
6.notify 和 notifyAll的区别 notify方法只唤醒一个等待(对象的)线程并使该线程开始执行.所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统 ...
- java中的异常种类和区别以及处理机制和区别
java中的异常种类和区别以及处理机制和区别 按照异常需要处理的时机分为编译时异常(也叫强制性异常)也叫 CheckedException 和运行时异常(也叫非强制性异常)也叫 RuntimeExce ...
最新文章
- (zt)Web 2.0奔路进行时
- hdu 1306(字符串匹配)
- 2021年春季学期-信号与系统-第二次作业参考答案-第三小题
- Lintcode107 Word Break solution 题解
- sql导入excel数据失败_nifi入门从Excel数据导入ES开始
- 请求WebApi的几种方式
- [css] 如何解决IE6浮动时产生双倍边距的BUG?
- 招聘 | 大疆算法类未来大咖招聘
- synchronized的使用(一)
- vmware 里MAC 鼠标能移动 无法单击
- Git-第五篇廖雪峰Git教程学习笔记(4)分支
- Linux学习初识redhat7(一)
- SQL盲注(原理概述、分类)
- 引领数字医学高地,中山医院探索打造未来医院“新范式”
- 发光二极管(一)- 基础知识
- 信噪比db换算_DB和dBm有哪些区别 DB和dBm区别介绍【图文】
- ps 自动生成html代码,详解使用PS中直接生成html网页保存样式的步骤
- ADAMoracle去中心化预言机价值核心在哪
- 2021-10-09烧录固件芯片操作流程
- Python中利用Opencv进行车牌号检测
热门文章
- OpenFOAM类库介绍(四)对流项
- C#之基于winform窗体绘制简单图形
- 线性规划模型详解及实际应用反思
- 区块链+珠宝供应链金融:除了解决信任问题,他们想让数字资产流动起来
- 登录安全----双重MD5加密实现安全登录
- 微信小程序怎么添加底部菜单按钮
- scikit-learn安装步骤
- 蓝天白云青山绿水还有清风吹斜阳......
- alter database recover managed standby database 语句
- 无人驾驶真体验!老百姓都能打得到的“共享无人车”来了