Re: WaitForMultipleObject feature in Java
On Jun 11, 11:44 pm, yancheng.ch...@gmail.com wrote:
WaitForMultipleObject(CountDownLatch, StopLock) in method void
MyWait()
either one of the object being signaled, the thread will continue
execution.
I don't think there's a pre-existing feature in Java to do this. But
it is simple: use two threads, as follows. Say you want to do
aFoo.quackQuack() when either the lock on object locker1 or the lock
on object locker2 is released, whichever comes first.
Code elsewhere:
Thread code:
private Object lock;
private Foo theFoo;
private boolean hasQuackQuackedTheFoo;
private Set<QuackerThread> threadSet;
public QuackerThread (Object lock, Foo theFoo) {
this.lock = lock;
this.theFoo = theFoo;
hasQuackQuackedTheFoo = false;
threadSet = new HashSet<QuackerThread>();
threadSet.add(this);
}
public QuackerThread (Object lock, QuackerThread anotherThread) {
this.lock = lock;
this.theFoo = anotherThread.theFoo;
hasQuackQuackedTheFoo = false;
threadSet = anotherThread.threadSet;
threadSet.add(this);
}
public boolean hasTheFooBeenQuackQuacked () {
return hasQuackQuackedTheFoo;
}
public void run () {
lock.wait();
quackQuackTheFooIfNecessary();
doWhateverElse();
}
public void quackQuackTheFooIfNecessary () {
synchronized (threadSet) {
for (QuackerThread t : threadSet) if
(t.hasTheFooBeenQuackQuacked()) return;
theFoo.quackQuack();
hasQuackQuackedTheFoo = true;
}
}
and elsewhere ...
QuackerThread t1 = new QuackerThread (locker1, aFoo);
QuackerThread t2 = new QuackerThread (locker2, t1);
(new Thread(t1)).start();
(new Thread(t2)).start();
t1 will be created with lock == locker1, theFoo == aFoo, and threadSet
a set containing just t1.
t2 will be created with lock == locker2, theFoo == aFoo (because
t1.theFoo == aFoo), and threadSet the same set containing just t1, and
add itself to that set, so that t1 and t2 both reference the same
Set<QuackerThread> containing just t1 and t2.
As soon as one of locker1 or locker2 is notified, t1 or t2
(respectively) will wake up and enter the critical section locked by
threadSet's monitor. It will find out if either of the threads has
already quackQuacked aFoo, and if neither has, it will quackQuack it
and put up its own quackQuacked flag. When the second of the lock
objects is notified, the other thread will enter the critical section.
It will have to wait for the first one to leave, and will then find on
polling that that thread has quackQuacked aFoo already, and simply
return.
So, aFoo gets quackQuacked exactly once, as soon as either of the two
locks is released, without getting quackQuacked a second time when the
second lock is released. doWhateverElse on the other hand is run once
for each thread when its respective lock has been notified.
This can be extended to three or more locks:
QuackerThread t3 = new QuackerThread(locker3, t1) or
QuackerThread t3 = new QuackerThread(locker3, t2) followed by
(new Thread(t3)).start()
should lead to a single quackQuacking whenever the first of the three
objects is notified, and so forth; the constructor that takes a
preexisting QuackerThread adds the new thread to whichever pool
contains the existing thread with the property that as soon as any of
the lock objects passed to any of their constructors is notified, the
quackQuack occurs, and only the once due to that pool. The other
constructor makes a QuackerThread in a pool by itself, to use as a
starting point for building a larger pool, or to quackQuack when a
single specific object gets notified, whichever.
This lets you quackQuack on a "logical OR" of object notifications. If
quackQuack does "someThing.notify()" this lets you cause the
notification of any of a set of objects notify "someThing", but only
the once.
public class NotifyOr extends Foo {
private Object thingToNotify;
public NotifyOr (Object thingToNotify, Set<Object> things) {
this.thingToNotify = thingToNotify;
QuackerThread t = null;
for (Object o : things) {
if (t == null)
t = new QuackerThread(o, this);
else
t = new QuackerThread(o, t);
(new Thread(t)).start();
}
}
public void quackQuack () {
thingToNotify.notify();
}
}
It's comparatively very easy to build a "NotifyAnd":
public class NotifyAnd implements Runnable {
private Object thingToNotify;
private Set<Object> things;
public NotifyAnd (Object thingToNotify, Set<Object> things) {
this.thingToNotify = thingToNotify;
this.things = things;
(new Thread(this)).run();
}
public void run () {
for (Object o : things) o.wait();
thingToNotify.notify();
}
}