Почему метод thenAccept() CompletableFuture не работает в основном потоке

Я обрабатываю длительную операцию внутри SupplyAsync() CompletableFuture и получаю результат в thenAccept(). Иногда thenAccept() выполняется в основном потоке, но некоторое время он работает в рабочем потоке. Но я хочу запустить операцию thenAccept() только в основном потоке. это пример кода.

private void test() {

    ExecutorService executorService = Executors.newSingleThreadExecutor();

    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync | I am running on : " + Thread.currentThread().getName());
        return "Hello world";
    }, executorService);

    CompletableFuture<Void> cf3 = cf1.thenAccept(s -> {
        System.out.print("thenAccept | I am running on : " + Thread.currentThread().getName());
        System.out.println(" | answer : " + s);
    });

    cf3.thenRun(() -> {
        System.out.println("thenRun | I am running on : " + Thread.currentThread().getName());
        System.out.println();
    });

}

public static void main(String[] args) {

    App app = new App();
    for(int i = 0; i < 3; i++){
        app.test();
    }
}

результат:

supplyAsync | I am running on : pool-1-thread-1
thenAccept | I am running on : main | answer : Hello world
thenRun | I am running on : main

supplyAsync | I am running on : pool-2-thread-1
thenAccept | I am running on : main | answer : Hello world
thenRun | I am running on : main

supplyAsync | I am running on : pool-3-thread-1
thenAccept | I am running on : pool-3-thread-1 | answer : Hello world
thenRun | I am running on : pool-3-thread-1

Как я могу это исправить ?


person Tharanga    schedule 02.05.2016    source источник
comment
Почему вы хотите это сделать?   -  person sisyphus    schedule 02.05.2016
comment
Спасибо. Предположим, что в методе thenAccept() я получаю доступ к общему ресурсу. Затем я должен подумать о безопасности потока ресурса. Функция executeBlocking Vert.x похожа на это. Они правильно с этим справляются.   -  person Tharanga    schedule 02.05.2016
comment
Ну, «правильно» может быть в глазах смотрящего. Если вы обращаетесь к общим ресурсам асинхронно, кажется, вам нужно беспокоиться о безопасности потоков. Возможно, вам следует разрешать доступ к общему ресурсу только через монитор, который планирует задачи в одном потоке.   -  person sisyphus    schedule 02.05.2016


Ответы (1)


Взгляните на JavaDoc CompletableFuture. Интересная часть касается политик CompletionStage.

Там вы обнаружите, что использование неасинхронного метода приводит к своего рода сценарию "или-или". Если вы затем посмотрите на реализацию, вы окажетесь в закрытой части Java Runtime. Существует некоторая НЕБЕЗОПАСНАЯ обработка, которая подразумевает, что может произойти какое-то состояние гонки.

Я бы предложил использовать варианты thenAcceptAsync() и thenRunAsync() и передать переменную executorService в оба вызова.

person Alexander    schedule 02.05.2016
comment
Завершается ли основной поток до того, как будут выполнены все CompletableFuture задачи? Кроме того, можете ли вы опубликовать «интересную часть» CompletableFuture javadoc? - person Kevin S; 16.03.2017