Получи случайную криптовалюту за регистрацию!

Правильный вариант: может быть и true и false Дело в том, что | Java Interview Tasks

Правильный вариант: может быть и true и false

Дело в том, что вызов thenRun у того же future, но во втором потоке, может привести к срабатыванию callback в первом thenRun.
При этом callback первого thenRun будет вызван во втором потоке.

Это происходит в тот момент, когда future.complete(null) начало выполняться, но ещё не успело вызвать callbacks,
а во втором потоке вызвался thenRun, который и выполнит все остальные callbacks на этом future но уже в своём потоке.

Проблем решается просто:

//основной поток
Thread mainThread = Thread.currentThread();

//создаём второй поток
Executor executor = Executors.newSingleThreadExecutor();

CompletableFuture future = new CompletableFuture<>();
CompletableFuture secondThreadFuture = future.thenRun(() -> {
System.out.println(Thread.currentThread() == mainThread);
});

//просто добавляем callback к тому же future в другом потоке
executor.execute(() -> {
secondThreadFuture.thenRun(() -> {
//nop
});
});

//завершаем future
future.complete(null);

Мы просто добавили secondThreadFuture, которая зависит от результата исходной future.
И вызов на ней thenRun во втором потоке не приводит к возможному срабатыванию callbacks на исходной future.

Для гарантированного вызова callbacks в заданных пользователем потоках у CompletableFuture существуют async реализации методов,
например — thenRunAsync, которым нужно передавать Executor. Но async-версии методов могут работать медленней, чем обычные.