0

I'm implementing the Future interface for shared computation. I.e. one thread performs the computation and other threads needed the same result just ask for it through the Future. So, I've read the Object#wait() method documentation and decided that it perfectly satisfies my needs. Here's how my implementation of the Future#get() method looks:

public class CustomFuture implements Future<Collection<Integer>> {

    private AtomicBoolean started;
    private Exception computationException;
    private boolean cancelled;
    private Collection<Integer> computationResult;
    private Object waitForTheResult = new Object();

    public Collection<Integer> get(){
        if(started.compareAndSet(false, true))
            //start the computation    //notifyAll() is called after finishing the computation here.
        while(computationResult == null){
            if(cancelled)
                throw new CancellationException();
            if(computationException != null)
                throw new ExectuonException();
            synchronized(waitForTheResult){
                waitForTheResult.wait();
            }
        }
        return computationResult;
    }             
    //The rest of methods
}

I'm not sure if the implementation is good, because of relying on low-level primitives. I thought that, as a rule of thumb, we should avoid using such a low-level primitives. Maybe that's the case where it's reasonable.

Maybe there's a better alternative of wait() in java.util.concurrent.

St.Antario
  • 26,175
  • 41
  • 130
  • 318
  • Your code is probably broken, either you want another process to notify you, and thus you don't want `waitForTheResult` as private, or you just want to wait until a result is available, and in this case you should use `sleep` instead of wait. – Holt Sep 29 '15 at 12:58
  • 2
    No. Low-level primitives like wait() and notify() are intended to be use in implementing higher level synchronization objects like Futures. The main thing you want to ask yourself, anytime you reach for such a low-level tool is, "Am I re-inventing the wheel?" That is, Is there a higher-level class already defined in a library somewhere that meets my needs? – Solomon Slow Sep 29 '15 at 13:09
  • I would consider `CountDownLatch` of `java.util.concurrent` a better alternative. – SpaceTrucker Sep 29 '15 at 13:14
  • @jameslarge So, am I? Maybe I missed something that's already existed...? – St.Antario Sep 29 '15 at 13:30
  • I don't know: Why are you implementing Future? Have you looked at any of the standard library classes and methods that return Futures? (e.g., the `java.util.concurrent.ThreadPoolExecutor` class which implements the `java.util.concurrent.ExecutorService` interface) – Solomon Slow Sep 29 '15 at 20:10

2 Answers2

5

No is not bad to use low level synchronization functions.

In your code I don't see the notify. If you go in wait another thread needs to notify to wake up the waiting thread.

If waitForTheResult is a private Object probably it can't be accessed from external, so how you implement the notify when the result has been calculated?

Davide Lorenzo MARINO
  • 26,420
  • 4
  • 39
  • 56
1

I now two way which would use facilites from the java.util.concurrent:

If you want to collect data from the main thread you could use the ExecutorCompletionService in Java. Just submit every Future to the Service and wait for the completion an collect the results.

ExecutorService ex = Executors.newFixedThreadPool(MAX_THREADS);
ExecutorCompletionService<MyResults> ecs = new ExecutorCompletionService<MyResults>(ex);

ecs.submit(new MyWorker());
ex.shutdown();
ex.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);

for (int x = 0; x < NUM_TASKS; ++x) {
    MyResult sr = ecs.take().get();
}

A different approach would be the usage of ReentrantLock which is a threadsafe lock, which can be aquired by a thread and which allows other threads wo wait for the lock to be unlocked again

ReentrantLock lock = new ReentrantLock();

// thread one
if(lock.tryLock(Long.MAX_VALUE, TimeUnit.SECONDS)){
    // aquire lock
    lock.lock();
    // do computation
}
// after computation
lock.unlock();

// Thread two
if(lock.tryLock(Long.MAX_VALUE, TimeUnit.SECONDS)){
    // get results
    lock.lock();
}
// after computation
lock.unlock();

This allows you to build some kind of chain of threads which wait for each other.

Westranger
  • 1,308
  • 19
  • 29