在自定义派生连接池上使用超时调用ForkJoinTask.get时,不接受超时

时间:2019-03-05 20:52:04

标签: java forkjoinpool

在我的代码中,我创建一个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

     */

0 个答案:

没有答案