永发信息网

java中的notify和notifyAll有什么区别

答案:2  悬赏:80  手机版
解决时间 2021-12-18 06:04
  • 提问者网友:精神病院里
  • 2021-12-17 12:52
java中的notify和notifyAll有什么区别
最佳答案
  • 五星知识达人网友:醉吻情书
  • 2021-12-17 14:03
首先从名字可以了解,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();
    }
}
全部回答
  • 1楼网友:舍身薄凉客
  • 2021-12-17 15:34
notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。notifyall 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。这些方法可以使用于“生产者-消费者”问题,消费者是在队列中等待对象的线程,生产者是在队列中释放对象并通知其他线程的线程。
我要举报
如以上回答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
点此我要举报以上问答信息
大家都在看
推荐资讯