繁体   English   中英

如何唤醒等待相同条件的所有线程?

[英]How to wake up all threads waiting on same condition?

我有以下情况。 几个线程正在等待相同的条件。 当得到通知时,所有应该停止等待,更改标志并返回对象:

 public Object getObject(){
    lock.lock();
    try {
        while (check)){
            condition.await();
        }

        return returnObjectAndSetCheckToFalse();
    } finally {
        lock.unlock();
    }
}

但是这段代码不起作用,因为更快的线程可能会将check标志更改为false,而第二个更慢的线程将再次阻塞。 可能有一个逻辑,即两个等待线程都将被唤醒,它们都将check flag设置为false,并返回对象? 或许它是矛盾的?

最简单的方法是将wait更改为if语句,但是这很容易受到虚假唤醒的影响。

您可以使用CountDownLatchCyclicBarrier

使用Future也是一种可能性, FutureTask更具体。 它有一个方法get() ,可用于阻止代码执行,直到Future完成其工作,从而满足您的要求。

您还可以实现自己的Barrier,它会在循环中执行wait()直到满足某个条件。 实现该条件会触发notifyAll() ,循环将完成,所有线程都可以继续。 但这将重新发明轮子。

我认为你正在努力实现,使用Future s:

ExecutorService executor = Executors.newCachedThreadPool();

// producer
final Future<String> producer = executor.submit(new Callable<String>() {
    @Override
    public String call() throws Exception {
        Thread.sleep(5000);
        return "done";
    }
});

// consumers
for (int i = 0; i < 3; i++) {
    final int _i = i;
    executor.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println("Consumer "+_i+" starts.");
            try {
                String value = producer.get();
                System.out.println("Consumer "+_i+" ends: "+value);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

如果你运行它,你应该看到所有的消费者线程打印出他们的开始消息,然后暂停,然后消费者线程打印出他们已经完成。 显然你必须将产生getObject()值的任何东西改成Callable但我敢打赌这会简化代码,因为现在它将在程序上进行结构化,而不是将计算结果存储在共享中变量。 我也比使用手动锁定的任何代码更自信它的线程安全。

一种方法是使用wait()而不是condition.await() 然后使用notifyAll()唤醒线程。

理想情况下,您将继续使用导致线程休眠的条件对象,并调用方法signalAll()来唤醒所有线程。

在你的代码我只会添加:

public Object getObject(){
lock.lock();
try {
    while (check)){
        condition.await();
    }
        condition.signalAll();
    return returnObjectAndSetCheckToFalse();
} finally {
    lock.unlock();
}

}

我甚至会考虑在returnObjectAndSetCheckToFalse()方法中而不是在return语句之前使用condition.signalAll()的可能性。

据我所知,如果你的condition.await()返回,你需要从所有线程中的方法体返回。 这个丑陋的解决方案应该有所帮助,尽管我认为有更好的解决方法:

public Object getObject() {
  lock.lock();
  try {
    int localstate = this.state;

    while (check && localstate == this.state)) {
      condition.await(); // all threads that are waiting here have the same state
    }

    if (!check) {
      this.state++; // first thread will change state thus making other threads ignore the 'check' value
    }

    return returnObjectAndSetCheckToFalse();
  } finally {
    lock.unlock();
  }
}

确实这是矛盾的。 你想要实现的是有问题的。 你希望在条件上等待的线程应该得到结果并继续,但是一个在通知之后不会调用getObject的线程。 至少,这是不公平的。 该线程是否设法在通知之前调用getObject ,是纯随机的。 你应该减少不确定性,而不是增加它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM