我如何在一个对象上等待()然后在另一个对象上进行notifyAll?

时间:2010-11-29 03:53:46

标签: java concurrency locking monitoring deadlock

我相信我面临的问题是嵌套式监视器锁定的变体。基本上我有两组线程(不是ThreadGroups,只是逻辑组)。一组线程(假设后台组)将等待一个对象,而另一组线程正在工作(工作组)。工作线程一个接一个地完成,直到最后一个工作线程处于'完整'方法中。我想要做的是找出告诉这个最后一个工作线程要等待的方法,然后然后调用notifyAll()来唤醒所有后台线程。正如您可能猜到的那样,两组线程正在来回切换 - 一组正在工作而另一组正在等待,然后组切换。问题是,如果我在当前等待的线程上发出notifyAll(),则无法保证最终工作线程将在通知线程完成之前进入wait()调用并尝试启动下一次交换。

很抱歉,如果这个问题有点过时 - 似乎我对并发的工作越多,我的代码就越复杂:(

4 个答案:

答案 0 :(得分:2)

听起来你需要类似Gate类的东西,它由两个CountDownLatch实例组成。我在很多多线程测试中使用类似的东西。

您的等待线程全部呼叫gate.ready(),工作人员完成后呼叫gate.go()

请注意,此特定实现假定1个协调器线程。要支持更多,只需使用您需要的服务器线程数构造go锁存器。

/**
 * Simple starting gate for co-ordinating a bunch of threads.
 */
final class Gate {
  final CountDownLatch ready;
  final CountDownLatch go = new CountDownLatch(1);

  Gate(final int threads) {
    ready = new CountDownLatch(threads);
  }

  /**
   * Called from the racing threads when ready. They will then block until all
   * threads are at this point;
   */
  void ready() {
    ready.countDown();
    await(go);
  }

  /**
   * Called from the starter thread. Blocks until everybody is ready, and then
   * signals go.
   */
  void go() {
    await(ready);
    go.countDown();
  }

  static void await(final CountDownLatch latch) {
    try {
      if (!latch.await(5, TimeUnit.SECONDS)) { // arbitrary, parameterise for production use
        throw new TimedOutException()
      }
    } catch (final InterruptedException e) {
      throw new RuntimeException(e);
    }
  }

  static final class TimedOutException extends IllegalStateException {}
}

如果您需要未知的任意线程数,您可能需要类似Doug Lea的Phaser类来自Java7。

答案 1 :(得分:1)

您可以尝试使用Exchanger连接线程组。它通常用于在两个交替工作的线程之间来回传输工作。如果您可以使转移工作正常,您似乎也可以使其适用于线程组。

如果每个组都有一个控制器线程怎么办?然后,当他在Exchanger中收到一个项目,然后加入他自己的所有组时,您可以让控制器notifyAll在他的组中。当连接全部返回时,他可以将控制权转移回交换器。

或者如果每个组中的线程数是固定的,您可以为具有固定线程数的组创建CyclicBarrier,然后指定在所有线程完成并命中时要运行的屏障操作障碍。该操作可以通过Exchanger或SynchronousQueue(这是一个强制执行同步协调的0长队列)来转移控制。

有关同步器的详细信息,请查看Java Concurrency in PracticeDZone concurrency refcard

答案 2 :(得分:0)

也许您可以使用一些变量来指示仍在工作的线程数。因此,当线程完成时,它使用以下方法:

synchronized void completed() {
    threads_working--;
    if (threads_working == 0) {
        synchronized (some_lock) {
            some_lock.notifyAll();
        }
    }
}
     

每个线程在开始工作时都会增加该数字。

答案 3 :(得分:0)

是否可以允许线程返回并终止而不是让它们等待?如果是这样,您是否考虑过实现线程管理器来生成线程并启动对每个组的控制?

线程进程:

public void run()
{
    while (workRemaining())
    {
        doWork();
    }
    this.manager.workCompleted();
}

并在线程管理器中:

void workCompleted()
{
    if (--this.runningThreads <= 0)
    {
        spawnNewGroup();
    }
}

void spawnNewGroup()
{
    for (int i=0; i<groupSize; i++)
    {
        startIndividualThread();
        this.runningThreads++;
    }
}