Question: Imagine that we have the following dummy code:

```
CompletableFuture<BigInteger> cf1 = CompletableFuture.supplyAsync(() -> BigInteger.valueOf(2L));
CompletableFuture<BigInteger> cf2 = CompletableFuture.supplyAsync(() -> BigInteger.valueOf(3L));
cf1.thenCombine(cf2, (x, y) -> x.add(y)).thenAccept(System.out::println);

```

Does JVM know that `cf1` and `cf2` carry independent threads in this case? And what will change if threads will be dependent (for example, use one connection to database)? 

More general, how does `CompletableFuture` synchronize threads?

Answer: 
I don't think that a CompletableFuture (CF) "synchronizes threads". It uses the executor [you have provided](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#supplyAsync-java.util.function.Supplier-java.util.concurrent.Executor-) or the [common pool](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html#commonPool--) if you have not provided one.

When you call `supplyAsync`, the CF submits the various tasks to that pool which in turns manages the underlying threads to execute the tasks.
It doesn't know, nor does it try to synchronize anything. It is still the client's responsibility to properly synchronize access to mutable shared data.