[ACCEPTED]-Wait until any of Future<T> is done-concurrency
Why not just create a results queue and 3 wait on the queue? Or more simply, use 2 a CompletionService since that's what it 1 is: an ExecutorService + result queue.
This is actually pretty easy with wait() and 8 notifyAll().
First, define a lock object. (You 7 can use any class for this, but I like to 6 be explicit):
package com.javadude.sample;
public class Lock {}
Next, define your worker thread. He 5 must notify that lock object when he's finished 4 with his processing. Note that the notify 3 must be in a synchronized block locking 2 on the lock object.
package com.javadude.sample;
public class Worker extends Thread {
private Lock lock_;
private long timeToSleep_;
private String name_;
public Worker(Lock lock, String name, long timeToSleep) {
lock_ = lock;
timeToSleep_ = timeToSleep;
name_ = name;
}
@Override
public void run() {
// do real work -- using a sleep here to simulate work
try {
sleep(timeToSleep_);
} catch (InterruptedException e) {
interrupt();
}
System.out.println(name_ + " is done... notifying");
// notify whoever is waiting, in this case, the client
synchronized (lock_) {
lock_.notify();
}
}
}
Finally, you can write 1 your client:
package com.javadude.sample;
public class Client {
public static void main(String[] args) {
Lock lock = new Lock();
Worker worker1 = new Worker(lock, "worker1", 15000);
Worker worker2 = new Worker(lock, "worker2", 10000);
Worker worker3 = new Worker(lock, "worker3", 5000);
Worker worker4 = new Worker(lock, "worker4", 20000);
boolean started = false;
int numNotifies = 0;
while (true) {
synchronized (lock) {
try {
if (!started) {
// need to do the start here so we grab the lock, just
// in case one of the threads is fast -- if we had done the
// starts outside the synchronized block, a fast thread could
// get to its notification *before* the client is waiting for it
worker1.start();
worker2.start();
worker3.start();
worker4.start();
started = true;
}
lock.wait();
} catch (InterruptedException e) {
break;
}
numNotifies++;
if (numNotifies == 4) {
break;
}
System.out.println("Notified!");
}
}
System.out.println("Everyone has notified me... I'm done");
}
}
As far as I know, Java has no analogous 19 structure to the WaitHandle.WaitAny
method.
It seems to me 18 that this could be achieved through a "WaitableFuture" decorator:
public WaitableFuture<T>
extends Future<T>
{
private CountDownLatch countDownLatch;
WaitableFuture(CountDownLatch countDownLatch)
{
super();
this.countDownLatch = countDownLatch;
}
void doTask()
{
super.doTask();
this.countDownLatch.countDown();
}
}
Though 17 this would only work if it can be inserted 16 before the execution code, since otherwise 15 the execution code would not have the new 14 doTask()
method. But I really see no way of doing 13 this without polling if you cannot somehow 12 gain control of the Future object before 11 execution.
Or if the future always runs in 10 its own thread, and you can somehow get 9 that thread. Then you could spawn a new 8 thread to join each other thread, then handle 7 the waiting mechanism after the join returns... This 6 would be really ugly and would induce a 5 lot of overhead though. And if some Future 4 objects don't finish, you could have a lot 3 of blocked threads depending on dead threads. If 2 you're not careful, this could leak memory 1 and system resources.
/**
* Extremely ugly way of implementing WaitHandle.WaitAny for Thread.Join().
*/
public static joinAny(Collection<Thread> threads, int numberToWaitFor)
{
CountDownLatch countDownLatch = new CountDownLatch(numberToWaitFor);
foreach(Thread thread in threads)
{
(new Thread(new JoinThreadHelper(thread, countDownLatch))).start();
}
countDownLatch.await();
}
class JoinThreadHelper
implements Runnable
{
Thread thread;
CountDownLatch countDownLatch;
JoinThreadHelper(Thread thread, CountDownLatch countDownLatch)
{
this.thread = thread;
this.countDownLatch = countDownLatch;
}
void run()
{
this.thread.join();
this.countDownLatch.countDown();
}
}
If you can use CompletableFuture
s instead then there is CompletableFuture.anyOf
that 3 does what you want, just call join on the 2 result:
CompletableFuture.anyOf(futures).join()
You can use CompletableFuture
s with executors by calling 1 the CompletableFuture.supplyAsync
or runAsync
methods.
Since you don't care which one finishes, why 3 not just have a single WaitHandle for all 2 threads and wait on that? Whichever one 1 finishes first can set the handle.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.