Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通知可以多次唤醒同一线程吗?_Java_Multithreading_Synchronization_Notify - Fatal编程技术网

Java 通知可以多次唤醒同一线程吗?

Java 通知可以多次唤醒同一线程吗?,java,multithreading,synchronization,notify,Java,Multithreading,Synchronization,Notify,假设您在Java中有一个典型的生产者-消费者模式。为了提高效率,在队列中添加新元素时,您希望使用notify()而不是notifyAll()。如果两个生产者线程调用notify,是否保证两个不同的等待消费者线程将被唤醒?或者可能是两个notify()s在彼此之后不久触发,导致同一个消费者线程排队等待唤醒两次?我找不到API中描述其工作原理的部分。java是否有一些原子内部操作来唤醒线程一次 如果只有一个消费者在等待,那么第二个通知就会丢失,这没有问题 来自: 通知哪个线程的选择“是任意的,由实现

假设您在Java中有一个典型的生产者-消费者模式。为了提高效率,在队列中添加新元素时,您希望使用
notify()
而不是
notifyAll()
。如果两个生产者线程调用notify,是否保证两个不同的等待消费者线程将被唤醒?或者可能是两个
notify()
s在彼此之后不久触发,导致同一个消费者线程排队等待唤醒两次?我找不到API中描述其工作原理的部分。java是否有一些原子内部操作来唤醒线程一次

如果只有一个消费者在等待,那么第二个通知就会丢失,这没有问题

来自:

通知哪个线程的选择“是任意的,由实现自行决定”

对于唤醒线程来说,它几乎肯定不是一种“公平”(计算机科学和并行性中使用的术语)算法。完全有可能同一根线连续两次被唤醒。还请注意,虚假通知也是可能的


总的来说,我同意那些建议使用实现而不是自己这样做的评论。

是的,您所描述的可能会发生。

如中所述,
notify
唤醒任意线程。因此,如果您的线程已完成,并且在下一个
notify
之前调用了
wait
,那么它将是唤醒的任意候选线程之一

我对多线程应用程序有丰富的经验,我发现我使用以下两种模式之一:

  • 有多个休眠线程需要在一个事件中唤醒,它们的唤醒顺序并不重要。在本例中,我使用
    notifyAll
    唤醒它们

  • 有一个睡眠线程需要在事件中醒来。在这种情况下,我使用
    notify
    唤醒它

  • 如果我曾经遇到过有多个睡眠线程的情况,并且我只想唤醒其中一个线程,我会使用不同的设计来实现这一点。基本上,我自己构建了一些东西,这样运行时环境就不会做出任意的决定。我总是想知道到底什么会醒来

    我将一个设计分解为这两个场景中的一个,或者使用包中的某些内容。我从来没有遇到过虚假通知的问题,但我对用于锁定的对象也非常小心。我倾向于创建普通的
    对象
    实例,其唯一目的是作为锁定操作的目标,但偶尔我会使用一个类类型定义良好且在我控制下的对象。

    您可以使用它来获得公平到达订单策略。在界面中,您可以获得生产者-消费者行为。该类结合了这两种功能

    您应该使用,其中该模式已经实现

    int capacity = 10;
    boolean fair = true;
    new ArrayBlockingQueue(capacity, fair);
    

    我的回答包含一些特定于实现的信息。它基于我对Sun JVM和其他线程库行为的工作知识

    如果两个生产者线程调用notify,是否保证两个不同的等待消费者线程将被唤醒

    不,不是。不能保证会有消费者被唤醒。可以保证的是,如果有两个线程正在等待,那么将有两个不同的线程放入运行队列

    或者可能是两个
    notify()
    s在彼此之后不久触发,导致同一个消费者线程排队等待唤醒两次

    否。两次
    notify()
    调用不会导致同一使用者线程排队两次。但是,它可能会导致一个线程被唤醒,并且可能没有其他线程在等待,因此第二个
    notify()
    调用可能不会执行任何操作。当然,线程可能已经被唤醒,然后又重新返回等待,这样就可以获得第二个
    notify()
    调用,但我认为这不是您所要求的

    java是否有一些原子内部操作来唤醒线程一次

    对。
    线程
    代码有许多同步点。一旦一个线程收到通知,它就会移出
    wait
    队列。以后对
    notify()
    的调用将查看
    wait
    队列,而不会找到线程

    还有一点很重要。对于生产者/消费者模型,始终确保在
    while
    循环中测试条件。原因是存在与消费者的竞争条件,消费者在锁上被阻止,但没有等待条件

     synchronized (workQueue) {
         // you must do a while here
         while (workQueue.isEmpty()) {
             workQueue.wait();
         }
         workQueue.remove();
     }
    
    Consumer1
    可能正在等待
    workQueue
    Consumer2
    可能在
    synchronized
    处被阻止,但在运行队列中。如果将某个内容放入
    工作队列
    并调用
    workQueue.notify()
    Consumer2
    现在被放入运行队列,但在
    Consumer1
    后面,谁先到。这是一个常见的实现。因此,
    Consumer1
    将从
    workQueue
    中删除通知
    Consumer2
    的项目
    Consumer2
    必须再次测试
    workQueue
    是否为空,否则将抛出
    remove()
    ,因为队列再次为空。请看这里

    同样重要的是要认识到,已经记录了虚假唤醒,因此
    while
    循环可以防止线程在没有
    wait()
    调用的情况下被唤醒


    综上所述,如果您可以按照其他答案中的建议,通过使用
    阻止队列来减少生产者/消费者代码,那么您应该这样做。
    BlockingQueue
    代码已经解决了所有这些问题。

    为什么不使用BlockingQueue实现呢?我同意Mauricio的观点。尽可能避开等待()/notify()——这是一个充满竞争条件的大黄蜂窝