My goal is to understand how CompletableFuture works.
My expected result: If I do CompletableFuture.runAsync().thenRun().thenRunAsync(). The thread will be executed in sequence runAsync() -> thenRun() -> thenRunAsync().
My actual result: The sequence is race condition. Sometimes:
runAsync -> thenRunAsync+e -> ...
runAsync -> thenRun -> ...
Reference from SO
public class RunExample5 {
public static void main(String[] args) {
ExecutorService e = Executors.newSingleThreadExecutor(r -> new Thread(r, "sole thread"));
CompletableFuture<?> f = CompletableFuture.runAsync(() -> {
System.out.println("runAsync:\t" + Thread.currentThread());
LockSupport.parkNanos((int) 1e9);
}, e);
f.thenRun(() -> System.out.println("thenRun:\t" + Thread.currentThread()));
f.thenRunAsync(() -> System.out.println("thenRunAsync:\t" + Thread.currentThread()));
f.thenRunAsync(() -> System.out.println("thenRunAsync+e:\t" + Thread.currentThread()),
e);
LockSupport.parkNanos((int) 2e9);
e.shutdown();
}
}
You need
f.thenRun(() -> System.out.println("thenRun:\t" + Thread.currentThread()))
.thenRunAsync(() -> System.out.println("thenRunAsync:\t" + Thread.currentThread()))
.thenRunAsync(() -> System.out.println("thenRunAsync+e:\t" + Thread.currentThread()), e);
The interface to CompletableFuture doesn't work quite the way you're imagining. f itself doesn't keep track of every call to thenRun or thenRunAsync and run them in order; instead, it treats everything from thenRun or thenRunAsync as simultaneously runnable as soon as the main work completes. If you want to chain more complicated sequences of work, you need to use the return value of thenRun or thenRunAsync -- a CompletionStage object -- and call thenRunAsync on that.
Related
I am trying to learn the basics of RxJava2 library and right now I am stuck at the following moment:
I have generated myFlowable via Flowable.generate(...) and now I need to wait while all the tasks will finish its execution, before I can proceed further.
This is the code to showcase the problem:
myFlowable.parallel()
.runOn(Schedulers.computation())
.map(val -> myCollection.add(val))
.sequential()
.subscribe(val -> {
System.out.println("Thread from subscribe: " + Thread.currentThread().getName());
System.out.println("Value from subscribe: " + val.toString());
});
System.out.println("Before sleep - Number of objects: " + myCollection.size());
try {
Thread.sleep(1000);
System.out.println("After sleep - Number of objects: " + myCollection.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
I run through all my tasks and add the results to collection. And if I check the collection size right after myFlowable block then it will be different, if I check it after small Thread.sleep(). Is there any way to check that all the tasks finished its execution and we can proceed further? Any help or guidance will be greatly appreciated.
As RxJava is asynchronous the java code below observable will run while the observable will run in a different thread thets why if you want to be notified if Flowable has finished emitting data you should do that in RxJava stream. for that you have an operator .doOnComplete
here you have an example how to detect when stream is finished
Flowable.range(0, 100).parallel()
.runOn(Schedulers.computation())
.map(integer -> {
return integer;
})
.sequential()
.doOnComplete(() -> {
System.out.println("finished");
})
.subscribe(integer -> System.out.println(integer));
You could use an AtomicBoolean, initialize it to false and set it to true using doFinally().
doFinally() is called after the Observable signals onError or onCompleted or it gets disposed by the downstream.
Then sleep the main thread until completed value is true.
Using your example:
AtomicBoolean completed = new AtomicBoolean(false);
myFlowable.parallel()
.runOn(Schedulers.computation())
.map(val -> myCollection.add(val))
.sequential()
.doFinally(() -> completed.set(true))
.subscribe(val -> {
...
});
...
try {
while(!completed.get()){
Thread.sleep(1000);
...
}
...
} catch (InterruptedException e) {
e.printStackTrace();
}
Use Flowable::blockingSubscribe() - Runs the current Flowable to a terminal event, ignoring any values and rethrowing any exception.
http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#blockingSubscribe--
Say I have a method which takes a parameter and returns a Mono<Integer> that asynchronously completes. For example:
Random random = new Random();
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(16);
Mono<Integer> fetch(String a) {
return Mono.create(em -> {
scheduledExecutorService.schedule(() -> em.next(a + " result"),
10 + random.nextInt(50), TimeUnit.MILLISECONDS);
});
}
Say I have a Flux<String> that I can feed into the fetch method above and that can have a lot of elements.
Is there a way I can ensure that the method gets called in parallel, but limit the number of concurrent calls to a predefined number?
E.g. 4 in the above example, while I have 16 available threads - so I always keep 12 spare from this perspective.
Assuming by "feed into", you mean you are using flux.flatMap(this::fetch),
then you can set the flatMap concurrency by calling flux.flatMap(this::fetch, 4) instead.
Also, your code has two compile errors:
the return type of fetch Mono<Integer> does not match the type of item you are giving to the sink (a + " result"). I assume you meant Mono<String>
MonoSink does not have a .next method. I assume you meant .success
Given all of that, here's an example:
private Flux<String> fetchAll() {
return Flux.range(0, 50)
.map(i -> Integer.toString(i))
.flatMap(this::fetch, 4);
}
private Mono<String> fetch(String a) {
return Mono.create(em ->
scheduledExecutorService.schedule(() -> em.success(a + " result"),
10 + random.nextInt(50), TimeUnit.MILLISECONDS)
);
}
I have two service calls:
String call1() { ... return "ok"; }
void call2(String) { ... }
I know the basic way for CompletableFuture with callback is like
CompletableFuture<Void> future = CompletableFuture
.supplyAsync(() -> call1())
.thenAccept(s -> call2(s));
future.join();
What if I separate the two chained CompletableFutures, like:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future1.join(); // will call2 be executed at this time?
Is this any different from calling join() on future2:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future2.join();
What if I call join() on both of the futures?
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future1.join();
future2.join();
It seems they are all the same from running my sample code. But I feel something might be wrong somewhere. Thanks!
They are not the same.
In short, you can look at it as future1 and future2 hold results of distinct tasks (even if future2 uses the result of future1, it's a different future).
future1.join() will block until () -> call1() ends, and future2's task won't start until then. future2.join() will wait until s -> call2(s) is done.
What if I separate the two chained CompletableFutures, like:
This makes no difference as far as task execution is concerned. It's either a question of style or it only matters when you need to use the two future objects separately.
What if I call join() on both of the futures?
It's redundant in this case to call future1.join() as you are not doing anything between the two .join calls. It would make sense if you wanted to perform some action "after completion of task1 and before the completion of task 2".
In this case, though, calling future2.join() is enough.
And the code snippet below should show how this behaves:
public static void main(String[] args) {
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> delay());
CompletableFuture<Void> future2 = future1.thenRun(() -> delay());
long start = System.currentTimeMillis();
future1.join();
System.out.println("Future 1 done. Waiting for future 2: "
+ (System.currentTimeMillis() - start));
future2.join();
System.out.println("Future 2 complete: "
+ (System.currentTimeMillis() - start));
}
static void delay() {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
As it is, this code outputs:
Future 1 done. Waiting for future 2: 5001
Future 2 complete: 10001
But when you remove future1.join(), the output becomes:
Future 2 complete: 10001
Which simply means that future1.join() is superfluous unless you have actions to perform between the completions of the two futures
The supplyAsync and thenAccept methods should be executed on a separate thread automatically according to the documentation:
All async methods without an explicit Executor argument are performed using the ForkJoinPool.commonPool()
In your examples, the only difference is your thread waits on different events before continuing due to the joining. Here is the breakdown:
CompletableFuture<Void> future = CompletableFuture
.supplyAsync(() -> call1())
.thenAccept(s -> call2(s));
future.join();
This will wait until call2 completes because that is the future returned by thenAccept method.
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future1.join(); // will call2 be executed at this time?
This will only wait until call1 completes and moves on. call2 will still gets executed.
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future2.join();
This is identical to the first one.
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future1.join();
future2.join();
Calling future1.join() ends when call1 completed, then future2.join() ends when call2 completed. This should be identical functionally with the first one as well.
Unlike stated in some blogs(e.g. I can't emphasize this enough: thenAccept()/thenRun() methods do not block) CompletableFuture.thenAccept can indeed block. Consider the following code, uncommenting the pause method call will cause thenAccept to block:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
log.trace("return 42");
return "42";
});
//pause(1000); //uncommenting this will cause blocking of thenAccept
future.thenAccept((dbl -> {
log.trace("blocking");
pause(500);
log.debug("Result: " + dbl);
}));
log.trace("end");
pause(1000);
Can we be sure that the following will not block? It's my understanding that if the supplyAsync runs immediately then the thenAccept could block, no?
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
return "42";
}).thenAccept((dbl -> {
pause(500);
log.debug("Result: " + dbl);
}));
You are right, thenAccept() will block if the future is already completed. Also note that when it is not the case, it will cause the thread that completes it to block at the time of completion.
This is why you have thenAcceptAsync(), which will run your Consumer in a non-blocking way:
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
return "42";
}).thenAcceptAsync((dbl -> {
pause(500);
log.debug("Result: " + dbl);
}));
See also Which executor is used when composing Java CompletableFutures?
I've been experimenting with different ways to handle blocking methods with disconnected results while maintaining state which might have been interrupted. I've found it to be frustrating having to deal with disparate classes and methods where sending and receiving are difficult to align.
In the following example, SomeBlockingMethod() normally returns void as a message is sent to some other process. But instead I've made it synchronized with a listener which receives the result. By spinning it off to a thread, I can wait() for the result with a timeout or indefinitely.
This is nice because once the result is returned, I can continue working with a particular state which I had to pause while waiting for the result of the threaded task.
This there anything wrong with my approach?
Although this question may seem generic, I am specifically looking for advice on threading in Java.
Example pseudocode:
public class SomeClass implements Command {
#Override
public void onCommand() {
Object stateObject = new SomeObjectWithState();
// Do things with stateObject
Runnable rasync = () -> {
Object r = SomeBlockingMethod();
// Blocking method timed out
if (r == null)
return;
Runnable rsync = () -> {
// Continue operation on r which must be done synchronously
// Also do things with stateObject
};
Scheduler().run(rsync);
};
Scheduler().run(rasync);
}
Update with CompletableFuture:
CompletableFuture<Object> f = CompletableFuture.supplyAsync(() -> {
return SomeBlockingMethod();
});
f.thenRun(() -> { () -> {
String r = null;
try {
r = f.get();
}
catch (Exception e) {
e.printStackTrace();
}
// Continue but done asynchronously
});
or better yet:
CompletableFuture.supplyAsync(() -> {
return SomeBlockingMethod();
}).thenAccept((
Object r) -> {
// Continue but done asynchronously
});
The problem with using strictly CompletableFuture is that CompletableFuture.thenAccept is run from the global thread pool and is not guaranteed to be synchronous with the calling thread.
Adding the scheduler back for the synchronous task fixes this:
CompletableFuture.supplyAsync(() -> {
return SomeBlockingMethod();
}).thenAccept((
Object r) -> {
Runnable rsync = () -> {
// Continue operation on r which must be done synchronously
};
Scheduler().run(rsync);
});
A caveat of using CompletableFuture compared to the complete scheduler method is that any previous state which exists outside must be final or effectively final.
You should check out RxJava, it uses stream manipulation and has threading support.
api.getPeople()
.observeOn(Schedulers.computation())
.filter(p -> return p.isEmployee();)
.map(p -> return String.format("%s %s - %s", p.firstName(), p.lastName(), p.payrollNumber());)
.toList()
.observerOn(<ui scheudler>)
.subscirbe(p -> screen.setEmployees(p);)