WaitForMultipleObject feature in Java

Y

yancheng.cheok

Current, I have a method, which will perform lock on

void MyWait()
{
CountDownLatch.aWait
// We can have access to the Stop lock.
}

void MyStop()
{
// Signal Stop lock.
}

This works fine until we need to stop the thread from keep waiting on
CountDownLatch, when there is a stop signal. (The method who send stop
signal doesn't have access to CountDownLatch, else, the stop method
can just directly signal the CountDownLatch)

We would like to have something, "if either CountDownLatch is signaled
or Stop lock is signaled", unblock the thread.

Perhaps something like

WaitForMultipleObject(CountDownLatch, StopLock) in method void
MyWait()

either one of the object being signaled, the thread will continue
execution.

May I know how can I do that in Java?

One of the solution is that I can interrupt the Thread which is halted
at line CountDownLatch.aWait. However, I have no access to the Thread
which halted at line CountDownLatch.aWait
 
T

Twisted

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();
}
}
 
Y

yancheng.cheok

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();

}
}

It look very complicated. I think I need to take sometime to digest,
test it out and get back to you.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top