Java notify和notifyAll的区别和相同

经常在往上逛,关于在java中notify和notifyAll,经常有人有以下的说法:

notify只会通知一个在等待的对象,而notifyAll会通知所有在等待的对象,并且所有对象都会继续运行

并且,好像都有例子可以证明。上面的说法,可以说对,也可以说不对。究其原因,在于其中有一点很关键,官方的说法如下所示:

wait,notify,notifyAll:

此方法只应由作为此对象监视器的所有者的线程来调用。通过以下三种方法之一,线程可以成为此对象监视器的所有者

通过执行此对象的同步实例方法。
通过执行在此对象上进行同步的 synchronized 语句的正文。
对于 Class 类型的对象,可以通过执行该类的同步静态方法。 
 一次只能有一个线程拥有对象的监视器。

以上说法,摘自javadoc。意思即,在调用中,必须持有对象监视器(即锁),我们可以理解为需要在synchronized方法内运行。那么由此话的隐含意思,即如果要继续由同步块包含的代码块,需要重新获取锁才可以。这句话,在javadoc中这样描述:

wait

此方法导致当前线程(称之为 T)将其自身放置在对象的等待集中,然后放弃此对象上的所有同步要求。出于线程调度
目的,在发生以下四种情况之一前,线程 T 被禁用,且处于休眠状态:
其他某个线程调用此对象的 notify 方法,并且线程 T 碰巧被任选为被唤醒的线程。
其他某个线程调用此对象的 notifyAll 方法。
其他某个线程中断线程 T。
大约已经到达指定的实际时间。但是,如果 timeout 为零,则不考虑实际时间,在获得通知前该线程将一直等待。
 然后,从对象的等待集中删除线程 T,并重新进行线程调度。然后,该线程以常规方式与其他线程竞争,以获得在该对
象上同步的权利;一旦获得对该对象的控制权,该对象上的所有其同步声明都将被恢复到以前的状态,这就是调用 wait
 方法时的情况。然后,线程 T 从 wait 方法的调用中返回。所以,从 wait 方法返回时,该对象和线程 T 的同步状态与调
用 wait 方法时的情况完全相同。

即必须重新进行获取锁,这样对于notifyAll来说,虽然所有的线程都被通知了。但是这些线程都会进行竞争,且只会有一个线程成功获取到锁,在这个线程没有执行完毕之前,其他的线程就必须等待了(只是这里不需要再notifyAll通知了,因为已经notifyAll了,只差获取锁了)有如下一个代码,可以重现这个现象。

首先,定义一个可以运行的线程类,如下所示:

private static final Object obj = new Object();
  static class R implements Runnable {
    int i;

    R(int i) {
      this.i = i;
    }

    public void run() {
      try {
        synchronized(obj) {
          System.out.println("线程-> " + i + " 等待中");
          obj.wait();
          System.out.println("线程-> " + i + " 在运行了");
          Thread.sleep(30000);
        }
      } catch(Exception e) {
        e.printStackTrace();
      }
    }
  }

注意上面的run方法内部,我们在wait()之后,打印一句话,然后将当前代码,暂停30秒。关于sleep方法,是这样描述的:
该线程不丢失任何监视器的所属权。
即仍然持有锁。

然后,定义一个main方法来运行这些线程,如下所示:

Thread[] rs = new Thread[10];
    for(int i = 0;i < 10;i++) {
      rs[i] = new Thread(new R(i));
    }
    for(Thread r : rs) {
      r.start();
    }

    Thread.sleep(5000);
    synchronized(obj) {
      obj.notifyAll();
    }

我们定义了10个线程,然后全部运行之。因为有wait,10个线程都会在打印出 “开始运行”之后等待。然后main方法调用notifyAll。这里的输出就会出现如下的输出:

线程-> 0 等待中
线程->  4 等待中
线程->  5 等待中
线程->  3 等待中
线程->  2 等待中
线程->  1 等待中
线程->  6 等待中
线程->  7 等待中
线程->  8 等待中
线程->  9 等待中
线程->  9 在运行了
...30秒之内,不会有其他输出

在上面的输出中,在wait之后,只有一个线程输出了”在运行了”语句,并且在一段时间内(这里为30秒),不会有其他输出。即表示,在当前代码持有锁之间,其他线程是不会输出的。

最后结论就是:被wait的线程,想要继续运行的话,它必须满足2个条件:

由其他线程notify或notifyAll了,并且当前线程被通知到了

经过和其他线程进行锁竞争,成功获取到锁了2个条件,缺一不可。其实在实现层面,notify和notifyAll都达到相同的效果,会有一个线程继续运行。但notifyAll免去了,线程运行完了通知其他线程的必要,因为已经通知过了。什么时候用notify,什么时候使用notifyAll,这就得看实际的情况了。

以上就是对Java notify和NotifyAll的资料整理,后续继续补充相关资料谢谢大家对本站的支持!

(0)

相关推荐

  • java多线程之wait(),notify(),notifyAll()的详解分析

    wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对象都有wait(),notify(),notifyAll()的功能.因为每个对象都有锁,锁是每个对象的基础,当然操作锁的方法也是最基础了. wait导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或被其他线程中断.wait只能由持有对像锁的线程来调用. notify唤醒在此对象监视器上等待的单个线程.如果所有线程都在此对象上等

  • Java中的notyfy()和notifyAll()的本质区别

    wait()方法表示,放弃当前对资源的占有权,等啊等啊,一直等到有人通知我,我才会运行后面的代码. notify()方法表示,当前的线程已经放弃对资源的占有, 通知等待的线程来获得对资源的占有权,但是只有一个线程能够从wait状态中恢复, 然后继续运行wait()后面的语句: notifyAll()方法表示,当前的线程已经放弃对资源的占有, 通知所有的等待线程从wait()方法后的语句开始运行. 读出什么区别没有? 上例子,先是一个nofiyAll()的例子: Java代码 package co

  • Java的wait(), notify()和notifyAll()使用心得

    wait(),notify()和notifyAll()都是java.lang.Object的方法:wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.notify(): Wakes up a single thread that is waiting on this object's

  • 基于Java多线程notify与notifyall的区别分析

    当一个线程进入wait之后,就必须等其他线程notify/notifyall,使用notifyall,可以唤醒所有处于wait状态的线程,使其重新进入锁的争夺队列中,而notify只能唤醒一个.注意,任何时候只有一个线程可以获得锁,也就是说只有一个线程可以运行synchronized 中的代码,notifyall只是让处于wait的线程重新拥有锁的争夺权,但是只会有一个获得锁并执行. 那么notify和notifyall在效果上又什么实质区别呢?主要的效果区别是notify用得不好容易导致死锁,

  • java notify和notifyAll的对比

     java notify和notifyAll 首先从名字可以了解,notify是通知一个线程获取锁,notifyAll是通知所有相关的线程去竞争锁. notify不能保证获得锁的线程,真正需要锁,并且可能产生死锁. 举例1: 所有人(消费者线程)准备吃饭,食堂没有开放(没有释放锁)打饭窗口(锁),所有人等待(WAITING). 食堂开饭打饭窗口(释放锁),并广播消息"开饭了"(notifyAll),所有人竞争排队,并等待吃饭(BLOCKED).每一个人依次在打饭窗口(获得锁)打饭(RU

  • Java notify和notifyAll的区别和相同

    经常在往上逛,关于在java中notify和notifyAll,经常有人有以下的说法: notify只会通知一个在等待的对象,而notifyAll会通知所有在等待的对象,并且所有对象都会继续运行 并且,好像都有例子可以证明.上面的说法,可以说对,也可以说不对.究其原因,在于其中有一点很关键,官方的说法如下所示: wait,notify,notifyAll: 此方法只应由作为此对象监视器的所有者的线程来调用.通过以下三种方法之一,线程可以成为此对象监视器的所有者 : 通过执行此对象的同步实例方法.

  • Java中notify和notifyAll的区别及何时使用

    提几个问题,从问题中去了解去学习: 他们之间有啥区别? 如果我使用notify(),将通知哪个线程? 我怎么知道有多少线程在等待,所以我可以使用notifyAll()? 如何调用notify()? 什么是这些线程等待被通知等? 我给点建议:建议使用jdk8里的lock包 java.util.concurrent.locks下的Condition 他可以支持唤醒指定的线程. 他只是一个接口 具体实现类是在AbstractQueuedSynchronizer 也就是AQS框架里的 你可以自己继承他

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

    notify() 和 notifyAll() 有什么区别? 先解释两个概念. 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池,等待池中的线程不会去竞争该对象的锁. 锁池:只有获取了对象的锁,线程才能执行对象的 synchronized 代码,对象的锁每次只有一个线程可以获得,其他线程只能在锁池中等待 然后再来说notify和notifyAll的区别 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程

  • Java多线程中wait、notify、notifyAll使用详解

    基础知识 首先我们需要知道,这几个都是Object对象的方法.换言之,Java中所有的对象都有这些方法. public final native void notify(); public final native void notifyAll(); public final native void wait(long timeout) throws InterruptedException; public final void wait() throws InterruptedExceptio

  • 详解Java中“==”与equals()的区别

    Java中"=="与equals()的区别 对于关系操作符"==",<Java编程思想>中是这样描述的:"关系操作符生成的是一个boolean结果,它们计算的是操作数的值之间的关系".这里的操作数的"值"值得我们注意.对于8种基本数据类型(boolean,byte,char,short,int,float,double,long),它们的变量直接存储的就是"值".所以,我们用"==&q

  • java equals和=,==的区别详细介绍

    Java中equals和==的区别 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值. 2.复合数据类型(类) 当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false. JAVA当中所有的类都是继承于Object这个基类的,在Ob

  • Java集合和数组的区别

    集合和容器都是Java中的容器. 区别 数组特点:大小固定,只能存储相同数据类型的数据 集合特点:大小可动态扩展,可以存储各种类型的数据 转换 数组转换为集合: Arrays.asList(数组) 示例: int[] arr = {1,3,4,6,6}; Arrays.asList(arr); for(int i=0;i<arr.length;i++){ System.out.println(arr[i]); } 集合转换为数组: 集合.toArray(); 示例: List list = ne

随机推荐