7

Vertx docs suggests to use executeBlocking() method when one needs to call blocking API. On the other hand Vertx also offers a notion of Future which basically do the same thing. But the executeBlocking() method isn't static. It is also not a simple wrapper around Future, and if you look at its implementation you'll see that it's pretty complex. What's the difference between these two?

Assume that I want to execute some long running task in an async way. Is there any difference between these two methods?

method 1:

doTheJob() {
    Future<Void> future = Future.future();
    executeLongRunningBlockingOperation();
    future.complete();
    return future;
}

doTheJob().setHandler(asyncResult -> {
    // ... handle result
});

method 2:

vertx.executeBlocking(future -> {
    executeLongRunningBlockingOperation();
    future.complete();
}, res -> {
    // ... handle result
});
homerman
  • 3,369
  • 1
  • 16
  • 32
Evan
  • 649
  • 1
  • 9
  • 22

1 Answers1

21

Your first example is not a correct usage of Future. The call to executeLongRunningBlockingOperation() will block the main thread until that method has completed — i.e. nothing else can happen until the blocking operation finishes. In your second example the blocking call is spun off into a background thread and other things continue to happen while it executes.

To illustrate this with a more complete example, this code:

public void executeLongRunningBlockingOperation() {
    Thread.sleep(5000);
}

public Future<Void> doTheJob() { 
    System.out.println("Doing the job...");
    Future<Void> future = Future.future();
    executeLongRunningBlockingOperation();
    // this line will not be called until executeLongRunningBlockingOperation returns!
    future.complete();
    // nor will this method! This means that the method won't return until the long operation is done!
    return future;
}

public static void main(String[] args) {
    doTheJob().setHandler(asyncResult -> {
        System.out.println("Finished the job");
    });
    System.out.println("Doing other stuff in the mean time...");
}

Will produce the following output:

Doing the job...
Finished the job
Doing other stuff in the mean time...

Whereas this code (using the executeBlocking):

...
public Future<Void> doTheJob() { 
    System.out.println("Doing the job...");
    Future<Void> future = Future.future();
    Vertx vertx = Vertx.vertx();
    vertx.executeBlocking(call -> {
        executeLongRunningBlockingOperation();
        call.complete;
    }, result -> {
        // this will only be called once the blocking operation is done
        future.complete();
    });
    // this method returns immediately since we are not blocking the main thread
    return future;
}
...

Will produce:

Doing the job...
Doing other stuff in the mean time...
Finished the job

If you'd like to develop a better understanding of Vert.x I'd recommend the following hands-on tutorials:

https://vertx.io/docs/guide-for-java-devs/

http://escoffier.me/vertx-hol/

Maxa
  • 236
  • 2
  • 4
  • Thx for the explanation. Now it's clear. Future is only about synchronization. It should be used for sequential composition. And `executeBlocking()` is just an equivalent of Callable. – Evan Oct 01 '18 at 03:45
  • Futures must be used asynchronously, for example [this method](https://github.com/vert-x3/vertx-guide-for-java-devs/blob/master/step-1/src/main/java/io/vertx/guides/wiki/MainVerticle.java#L86) returns a future and uses callbacks to complete it. `executeBlocking()` is used to run blocking code _as if_ it were asynchronous (i.e. make blocking code compatible with futures). – Maxa Oct 06 '18 at 01:13
  • @Maxa Both the links are non functional now. – lazilyInitialised Apr 20 '22 at 10:18
  • @Maxa but the github link shared above in the comment is relevant and works. Thanks! – lazilyInitialised Apr 20 '22 at 10:56
  • 1
    Thanks for the nice answer, but I suggest not to use Vertx vertx = Vertx.vertx(); because it will create a new instance and at scale will cause you to run out of file descriptors. Instead use Vertx.currentContext().owner(); – Key Lay Jan 31 '23 at 20:01