开发者

How can I wait() on one object and then notifyAll on another?

开发者 https://www.devze.com 2023-01-27 14:00 出处:网络
I believe the problem I am facing is a variant of the nested-monitor lockout. Basically I have two groups of threads (not ThreadGroups, just logical groups). One group of threads(let\'s say the backgr

I believe the problem I am facing is a variant of the nested-monitor lockout. Basically I have two groups of threads (not ThreadGroups, just logical groups). One group of threads(let's say the background group) will be waiting on an object while the other group of threads is working (the working group). One by one the working threads complete, until finally the last working thread is in the 'complete' method. What I want to do is figure out some method of telling this last working thread to wait, and then calling notifyAll() to wakeup all the background threads. As you can probably guess, the two groups of threads are being switched back and forth - one group is working while the other is waiting and then the groups switch. Problem is, if I notifyAll() on the currently waiting threads then there is no guarantee the final working thread will make it to th开发者_开发技巧e wait() call before the notified threads complete and try to start the next swap.

Sorry if this question is a bit off - seems the more I work on concurrency the more convoluted my code becomes :(


Sounds like you need something like a Gate class that is composed of two CountDownLatch instances. I use something similar in a lot of multi-threaded tests.

Your waiting threads all call gate.ready() and the the workers call gate.go() when done

Note this particular implementation assumes 1 coordinator thread. To support more, simply construct the go latch with the number of waiter threads you require.

/**
 * 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 {}
}

If you need unknown arbitrary thread counts you probably want something similar to Doug Lea's Phaser class coming in Java7.


You could try connecting the thread groups with an Exchanger. It's classically used for transferring work back and forth between two threads that alternate work. Seems like you might be able to make it work for groups of threads too if you can get the transfer to work right.

What if you had a controller thread for each group? You could then have the controller notifyAll on his group when he received an item in the Exchanger, then join on all of his own group. When the joins all return, he could transfer control back over the Exchanger.

Or if the number of threads in each group is fixed, you could create a CyclicBarrier for the group with the fixed number of threads, then specify a barrier action to be run when all of the threads complete and hit the barrier. That action could transfer control via an Exchanger or a SynchronousQueue (which is a 0-length queue that enforces synchronous coordination).

For more information on synchronizers, check out Java Concurrency in Practice or the DZone concurrency refcard.


Maybe you could use some variable to indicate number of still working threads. So, when the thread completes, it uses this method:

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

And every thread shall increment that number when it starts working.


Is it possible to allow the threads to return and terminate instead of having them wait? If so, have you considered implementing a thread manager to spawn the threads and initiate control to each group?

the threaded process:

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

and within the thread manager:

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

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号