`
y806839048
  • 浏览: 1127188 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

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(){

      

            @Override

            public 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(){

      

            @Override

            public void run(){

                test.go();

                System.out.println(Thread.currentThread() + " finished Execution");

            }

        };

      

        Thread t1 = new Thread(waitTask, "WT1"); //will wait

        Thread t2 = new Thread(waitTask, "WT2"); //will wait

        Thread t3 = new Thread(waitTask, "WT3"); //will wait

        Thread t4 = new Thread(notifyTask,"NT1"); //will notify

      

        //starting all waiting thread

        t1.start();

        t2.start();

        t3.start();

      

        //pause to ensure all waiting thread started successfully

        Thread.sleep(200);

      

        //starting notifying thread

        t4.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 wakeup

            System.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 up

            notifyAll(); // 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是没有任何影响的 

现在 你是不是可以随心所欲的唤醒你想唤醒的线程了? 都看到这了 还不给个赞吗

 

 

 

 

--------------------- 

 

原文:https://blog.csdn.net/u014658905/article/details/81035870 

 

分享到:
评论

相关推荐

    Java 同步方式 wait和notify/notifyall

    在Java中,`wait()`, `notify()`, 和 `notifyAll()` 是Java Object类的三个方法,它们在实现线程间通信和协作时扮演着关键角色。这些方法主要用于解决线程等待和唤醒的问题,是基于Java Monitor(监视器)模型的。 ...

    如何在Java中正确使用 wait, notify 和 notifyAll

     在 Java 中可以用 wait、notify 和 notifyAll 来实现线程间的通信。。举个例子,如果你的Java程序中有两个线程——即生产者和消费者,那么生产者可以通知消费者,让消费者开始消耗数据,因为队列缓冲区中有内容待...

    Java notify和notifyAll的区别和相同

    Java中的`notify`和`notifyAll`是多线程编程中的关键方法,它们用于线程间的通信,特别是在处理同步机制时。这两个方法都是在`Object`类中定义的,因此可以应用于任何Java对象。 首先,我们需要理解Java的同步机制...

    wait()、notify()和notifyAll()方法1---马克-to-win java视频

    wait()、notify()和notifyAll()方法1---马克-to-win java视频

    wait()、notify()和notifyAll()方法2---马克-to-win java视频

    wait()、notify()和notifyAll()方法2---马克-to-win java视频

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

    Java多线程中wait、notify、notifyAll使用详解 Java中多线程编程中,wait、notify、notifyAll三个方法是非常重要的,它们都是Object对象的方法,用于线程之间的通信。下面我们将详细介绍这三个方法的使用和作用。 ...

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

    Java中的多线程编程是构建高效并发应用的关键技术之一,其中`wait()`、`notify()`和`notifyAll()`是Java对象锁机制中的三个关键方法,它们位于`java.lang.Object`类中,主要用于线程间通信。本文将深入探讨`notify()...

    java notify和notifyAll的对比

    Java中的`notify`和`notifyAll`方法是多线程编程中的重要概念,它们都是`Object`类的方法,用于在同步控制中唤醒等待在特定对象监视器上的线程。理解这两个方法的区别对于编写高效的并发代码至关重要。 首先,`...

    源码—Java多线程5—死锁和wait notify notifyAll

    源码—Java多线程5—死锁和wait notify notifyAll

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

    Java中的`wait()`, `notify()`, 和 `notifyAll()` 是多线程编程中的关键工具,它们用于在并发环境中协调线程间的交互。这些方法都定义在`java.lang.Object`类中,因为它们与对象的监视器(monitor)概念密切相关。...

    Java 中Object的wait() notify() notifyAll()方法使用

    Java 中Object的wait() notify() notifyAll()方法使用 在Java并发编程中,Object的wait()、notify()和...wait()、notify()和notifyAll()方法是Java并发编程中非常重要的概念,理解它们的使用方法和价值是非常重要的。

    java之wait,notify的用法([ 详解+实例 ])

    在Java多线程编程中,wait和notify是两个非常重要的方法,它们都是Object类的方法,用于线程之间的通信和同步。下面我们将详细解释wait和notify的用法。 wait方法 wait方法是Object类的一个方法,用于让当前线程...

    Java多线程同步(wait()notify()notifyAll())[文].pdf

    本文将深入探讨Java中的wait()、notify()和notifyAll()方法,以及synchronized关键字和原子操作在多线程环境中的应用。 1. **wait()方法**: - wait()是Object类的一个方法,它的作用是让当前线程暂停执行并释放它...

    java中几个notify、wait使用实例

    `wait()`、`notify()`和`notifyAll()`方法是Java中实现线程同步的关键工具。正确使用它们可以有效避免线程间的竞争条件和死锁问题,同时也能实现线程间的高效通信。在实际开发中,应根据具体的应用场景选择合适的...

    java面试java-interview-guide-master.zip

    - 链表与数组的区别:理解两种数据结构的优缺点,以及何时选择哪种。 - 集合框架中的遍历方式:迭代器和增强for循环的使用。 - 并发集合:了解ConcurrentHashMap、CopyOnWriteArrayList等并发安全的集合。 4. **...

    java私塾面试题----JAVA代码与编程3

    4. **集合框架**:ArrayList、LinkedList、HashMap、HashSet、TreeMap等集合类的使用和区别,以及遍历、查找、删除等操作,面试中常会考察这些内容。 5. **多线程**:线程的创建(Thread类和Runnable接口)、线程...

    java面试题收集录--java面试没问题---来吧java对象

    面试中可能会问到如何设计一个类,如何实现多态性,以及何时使用抽象类与接口。 3. **集合框架**:集合是存储和管理数据的关键,包括ArrayList、LinkedList、HashSet、HashMap等。面试中可能需要解释它们之间的区别...

    JAVA---------笔试面试题

    5. **多线程:** 掌握线程的创建方式(实现Runnable接口和继承Thread类),线程同步机制(synchronized关键字、wait()、notify()、notifyAll()),以及线程池的使用。 6. **IO流:** 理解字节流和字符流的区别,...

    Core-Java-1.-Volume-I---Fundamentals.rar_Fundamentals

    书中详细讲解了如何创建和管理线程,包括同步机制(synchronized关键字和Lock接口)、线程通信(wait、notify和notifyAll方法)以及线程池的使用。 最后,本书还会涉及反射和泛型等高级主题。反射允许程序在运行时...

    java基础课件(1---10)

    9. **多线程**:学习线程的创建方式(继承Thread类和实现Runnable接口),线程同步机制(synchronized关键字,wait(), notify(), notifyAll()方法,以及Lock接口)以及线程池的使用。 10. **文件和目录操作**:学习...

Global site tag (gtag.js) - Google Analytics