在Java语言中notifyAll()方法的实际作用如下:
1.notifyAll(): Wakes up all threads that are waiting on this object’s monitor;
2.当一个线程使用的同步方法中用到某个变量,而此变量又需要其它线程修改后才能符合本线程的需要,则可以在同步方法中调用wait()方法,使本线程等待,并允许其它线程调用这个同步方法
3.其它线程在使用这个同步方法不需要等待,当它使用完这个同步方法时,用notifyAll()通知所有由于使用这个同步方法而处于等待的线程结束,再次使用这个同步方法
4.如果使第一个处于等待的线程结束等待,则调用方法notify()
Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点 。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。
Java中notify和notifyAll的区别
首先从名字可以了解,notify是通知一个线程获取锁,notifyAll是通知所有相关的线程去竞争锁。
notify不能保证获得锁的线程,真正需要锁,并且可能产生死锁。
举例1:
所有人(消费者线程)准备吃饭,食堂没有开放(没有释放锁)打饭窗口(锁),所有人等待(WAITING)。
食堂开饭打饭窗口(释放锁),并广播消息“开饭了”(notifyAll),所有人竞争排队,并等待吃饭(BLOCKED)。每一个人依次在打饭窗口(获得锁)打饭(RUNNABLE)。如果想吃饭就打完饭后离开(释放锁),不想吃饭就直接离开(释放锁)。如果吃完了还想吃,就主动等待下一次“开饭了”的消息(wait)。
食堂通知一个人来吃饭(notify),此人来到打饭窗口(获得锁)打饭(RUNNABLE),其他人都在等待开饭的消息(WAITING)。如果想吃饭就打完饭后离开(释放锁),不想吃饭就直接离开(释放锁)。如果吃完了还想吃,就主动等待下一次“开饭”的消息(WAITING)。
notify不能保证通知到真正想吃饭的人。
举例2:
两个生产者P1、P2,两个消费者C1、C2,共同操作一个队列,队列最大长度为1。
开始P1、P2、C1、C2都处于运行状态(RUNNABLE)。
C1先获得锁,P1、P2、C2为BLOCKED状态。C1发现队列为空,主动进入WAITING。C2接着获得锁,成为RUNNABLE状态,发现队列为空,主动进入WAITING。
P1接着获得锁,成为RUNNABLE状态,在队列中插入一个元素,notify到了另一个生产者P2。P1循环生产,发现队列不为空,成为WAITING。
P2成为RUNNABLE状态,发现队列有值,主动进入WAITING。
此时锁已被释放,但P1、P2、C1、C2都处于WAITING状态,没有线程去获取锁,死了。
notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。两者的最大区别在于:
notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
notify则文明得多他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁此时如果该对象没有再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。
下面是一个很好的例子:
import java.util.*
class Widget…{}
class WidgetMaker extends Thread…{
List<Widget> finishedWidgets=new ArrayList<Widget>()
public void run()…{
try…{
while(true)…{
Thread.sleep(5000)//act busy
Widget w=new Widget()
//也就是说需要5秒钟才能新产生一个Widget,这决定了一定要用notify而不是notifyAll
//因为上面两行代码不是同步的,如果用notifyAll则所有线程都企图冲出wait状态
//第一个线程得到了锁,并取走了Widget(这个过程的时间小于5秒,新的Widget还没有生成)
//并且解开了锁,然后第二个线程获得锁(因为用了notifyAll其他线程不再等待notify语句
//,而是等待finishedWidgets上的锁,一旦锁放开了,他们就会竞争运行),运行
//finishedWidgets.remove(0),但是由于finishedWidgets现在还是空的,
//于是产生异常
//***********这就是为什么下面的那一句不能用notifyAll而是要用notify
synchronized(finishedWidgets)…{
finishedWidgets.add(w)
finishedWidgets.notify() //这里只能是notify而不能是notifyAll
}
}
}
catch(InterruptedException e)…{}
}
public Widget waitForWidget()…{
synchronized(finishedWidgets)…{
if(finishedWidgets.size()==0)…{
try…{
finishedWidgets.wait()
}
catch(InterruptedException e)
…{}
}
return finishedWidgets.remove(0)
}
}
}
public class WidgetUser extends Thread…{
private WidgetMaker maker
public WidgetUser(String name,WidgetMaker maker)…{
super(name)
this.maker=maker
}
public void run()…{
Widget w=maker.waitForWidget()
System.out.println(getName()+”got a widget”)
}
public static void main(String[] args) …{
WidgetMaker maker=new WidgetMaker()
maker.start()
new WidgetUser(”Lenny”,maker).start()
new WidgetUser(”Moe”,maker).start()
new WidgetUser(”Curly”,maker).start()
}
}
如何在 Java 中正确使用 wait,notify 和 notifyAll
notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。这些方法可以使用于“生产者-消费者”问题,消费者是在队列中等待对象的线程,生产者是在队列中释放对象并通知其他线程的线程。
java notify() 与 notifyAll() 区别 以及前者的用法 举例
在 Java 中可以用 wait、notify 和 notifyAll 来实现线程间的通信。
1)利用wait()来让一个线程在某些条件下暂停运行。
例如,在生产者消费者模型中,生产者线程在缓冲区为满的时候,消费者在缓冲区为空的时 候,都应该暂停运行。
2)notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程。
3) notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程。
举个简单的例子:假如有三个线程Thread1、Thread2和Thread3都在等待对象objectA的monitor,此时Thread4拥有对象objectA的monitor,当在Thread4中调用objectA.notify()方法之后,Thread1、Thread2和Thread3只有一个能被唤醒。
注意,被唤醒不等于立刻就获取了objectA的monitor。假若在Thread4中调用objectA.notifyAll()方法,则Thread1、Thread2和Thread3三个线程都会被唤醒,至于哪个线程接下来能够获取到objectA的monitor就具体依赖于操作系统的调度。
首先:使用wait方法和使用synchornized来分配cpu时间是有本质区别的。wait会释放锁,synchornized不释放锁。
还有:(wait/notify/notifyAll)只能在取得对象锁的时候才能调用。
调用notifyAll通知所有线程继续执行,只能有一个线程在执行其余的线程在等待(因为在所有线程被唤醒的时候在synchornized块中)。这时的等待和调用notifyAll前的等待是不一样的。
notifyAll前:在对象上休息区内休息
notifyAll后:在排队等待获得对象锁。
notify和notifyAll都是把某个对象上休息区内的线程唤醒,notify只能唤醒一个,但究竟是哪一个不能确定,而notifyAll则唤醒这个对象上的休息室中所有的线程.
一般有为了安全性,我们在绝对多数时候应该使用notifiAll(),除非你明确知道只唤醒其中的一个线程.
至于有些书上说“notify:唤醒同一对象监视器中调用wait的第一个线程”我认为是没有根据的因为sun公司是这样说的“The choice is arbitrary and occurs at the discretion of the implementation.”
以上就是关于Java中notifyAll()方法的实际作用?全部的内容,如果了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!