При вызове ForkJoinTask.get с тайм-аутом в пользовательском пуле соединений форка тайм-аут не учитывается - PullRequest
0 голосов
/ 05 марта 2019

В моем коде я создаю ForkJoinTask, а в исполняемом файле этой задачи разветвляется новая задача и вызывается newTask.get (7, TimeUnit).Новое задание спит 10 секунд.Когда исходное задание отправляется в общий пул, я получаю исключение TimeoutException.Но при использовании пользовательского ForkJoinPool newTask.get (7, TimeUnit) ожидает завершения задачи.Кроме того, в случае commonPool, хотя я отменяю newTask, он все еще выполняется до завершения и не заканчивается InterruptedException.Это на Java 8.

Итак, вопросы: почему forkJoinTask.get (7, TimeUnit) игнорирует время ожидания в некоторых случаях, и почему forkJoinTask.cancel (true) не генерирует исключение InterruptedException?

public class ForkJoinQuestion {
    private static final long START = System.currentTimeMillis();
    private static final boolean COMMON_FORK_JOIN_POOL = false;
    private final ForkJoinPool service = COMMON_FORK_JOIN_POOL ? ForkJoinPool.commonPool() : new ForkJoinPool(1);

    public static void main(String[] args) throws InterruptedException {
        ForkJoinQuestion question = new ForkJoinQuestion();
        question.first();
        Thread.sleep(17000);
        System.out.println(time() + "Finished main");
    }

    private void first() {
        service.submit(() -> {
            System.out.println(time() + "Entered first");
            ForkJoinTask<?> next = second();
            next.fork();
            try {
                next.get(7000, TimeUnit.MILLISECONDS);
                sleep(1); // do some computations
                System.out.println(time() + "finished first");
            } catch (Exception e) {
                next.cancel(true);
                System.out.println(time() + "[Exception in first] " + e.toString());
                throw new RuntimeException(e);
            }
        });
    }

    private ForkJoinTask<?> second() {
        return ForkJoinTask.adapt(() -> {
            System.out.println(time() + "Entered second");
            sleep(10);
            System.out.println(time() + "finished second");
        });
    }

    private static void sleep(int numSeconds) {
        try {
            System.out.println(time() + "Waiting " + numSeconds + " seconds");
            Thread.sleep(numSeconds * 1000);
        } catch (InterruptedException e) {
            System.out.println(time() + "caught interrupted exception during sleep(" + numSeconds + ")");
        }
    }

    private static String time() {
        long time = System.currentTimeMillis() - START;
        return Long.toString(time) + " : " + Thread.currentThread().getName() + " : ";
    }

    /*


    When using the common pool the output is like this:

        48 : ForkJoinPool.commonPool-worker-1 : Entered first
        51 : ForkJoinPool.commonPool-worker-2 : Entered second
        51 : ForkJoinPool.commonPool-worker-2 : Waiting 10 seconds
        7053 : ForkJoinPool.commonPool-worker-1 : [Exception in first] java.util.concurrent.TimeoutException
        10055 : ForkJoinPool.commonPool-worker-2 : finished second
        17048 : main : Finished main

    Looks mostly good, but I was expecting that second would be cancelled so "finished second" should not be in the output.
    But when using a custom fork join pool, the timeout is not honored:

        47 : ForkJoinPool-1-worker-1 : Entered first
        50 : ForkJoinPool-1-worker-1 : Entered second
        50 : ForkJoinPool-1-worker-1 : Waiting 10 seconds
        10050 : ForkJoinPool-1-worker-1 : finished second
        10050 : ForkJoinPool-1-worker-1 : Waiting 1 seconds
        11050 : ForkJoinPool-1-worker-1 : finished first
        17050 : main : Finished main

     */
...