1

I want to return a CompletableFuture in one method, which will succeed only once a second method of that object is called with the result value, something like

public class Foo {
   private CompletableFuture<String> f;

   public CompletableFuture<String> method1() {
      f = CompletableFuture.waitForever???
      return f; 
   }

   public void method2(String s) {
      if (f != null) { 
         f.complete(s);
      }
   } 
}

Is this possible? Do I overlook a less crazy way to do that?

Landei
  • 54,104
  • 13
  • 100
  • 195

2 Answers2

1

You can use the Object.wait() method to achieve this behavior:

CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    try {
        synchronized (this) { // needed to prevent an IllegalMonotirStateException (see https://stackoverflow.com/a/1537133/8178842)
            wait();
        }
    }
    catch (InterruptedException e) {
        // should never happen
        throw new RuntimeException(e);
    }
});

A simple UnitTest shows the behavior:

@Test
public void test() {
    // create a CompeltableFuture that just waits
    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        try {
            synchronized (this) {// needed to prevent an IllegalMonotirStateException (see https://stackoverflow.com/a/1537133/8178842)
                wait(); // wait till the CompletableFuture.complete method is called (or till this thread is notified, what shouldn't happen)
            }
        }
        catch (InterruptedException e) {
            // should never happen
            throw new RuntimeException(e);
        }
    });
    
    new Thread(() -> {
        try {
            Thread.sleep(3000); // wait for three seconds
        }
        catch (InterruptedException e) {
            // ignore
        }
        
        // complete the future manually after three seconds
        future.complete(null);
    }).start();
    
    try {
        future.get(); // block until the future is completed
    }
    catch (InterruptedException | ExecutionException e) {
        // can be ignored here
    }

    // the future.get() method will be blocking for 3 seconds
}

Because of the suspended thread that completes the CompletableFuture, the test will wait for 3 seconds and then finish waiting.

Tobias
  • 2,547
  • 3
  • 14
  • 29
0

CompletableFuture#get() will wait forever until completion

from docs

Waits if necessary for this future to complete, and then returns its result.

thats why there is get(long timeout, TimeUnit unit) that allows to timeout

Waits if necessary for at most the given time for this future to complete, and then returns its result, if available.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • I know that `CompletableFuture#get` waits indefinitely on the caller side, but I need to give a CompletableFuture back which waits forever (until someone else - here `method2()` - sets it to complete). What should I return in my example instead of the non-existing `CompletableFuture.waitForever`? – Landei Aug 08 '18 at 06:52
  • *but I need to give a CompletableFuture back which waits forever* which waits doing what and what it supposed to do when it is completed? Should it block somewehere or what? – Antoniossss Aug 08 '18 at 06:55
  • The problem is that CompletableFuture does not wait by itself for anything nor completes itself. Something must complete it. It is a sort of synchronization cross point between producer and consumer. I would say it does what you require by design. Maybe you want to add 3rd, arbitrary party into play that first must allow for completable future to complete. IDK, its just unclear to me. – Antoniossss Aug 08 '18 at 07:03