## Future - 可以取消的任务

Future - 可以取消的任务

场景

在合并多个请求时,一般主函数都 会限制超时时间,如果超时,我们就认为子任务请求结束,但是,其实子任务可能还未真正结束,还在后台运行,且占用我们的线程数量。

现在要做的是如果主函数请求超时,那么对应的子任务也要被取消

CancelTaskManager

public class CancelTaskManager {

    private List<Future<?>> futures;
    private CountDownLatch latch;

    public CancelTaskManager(int taskSize) {
        this.futures = new LinkedList<>();
        latch = new CountDownLatch(taskSize);

    }

    public <T> CancelTaskManager addTask(Supplier<T> supplier, ExecutorService executor){
        Future<T> future = executor.submit(new InterruptableTask<T>(latch) {
            @Override
            public T get() {
                return supplier.get();
            }
        });
        futures.add(future);
        return this;
    }

    public void execute(long timeOut, TimeUnit unit, Consumer<List<Object>> callback)
                    throws ExecutionException, InterruptedException, TimeoutException {
        try {
            latch.await(timeOut, unit);
        } catch (InterruptedException e) {
            // ignore
        }
        boolean done = true;
        for (Future<?> future : futures) {
            if (!future.isDone()) {
                done = false;
                future.cancel(true);
                System.out.println("cancel " + future.hashCode());
            }
        }
        List<Object> result = new ArrayList<>();
        if (done) {
            for (Future<?> future : futures) {
                result.add(future.get(0, TimeUnit.SECONDS));
            }
            callback.accept(result);
        }
    }



    public abstract class InterruptableTask<T> implements Callable<T>, Supplier<T> {

        private CountDownLatch latch;

        public InterruptableTask(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public T call() throws Exception {
            try {
                T t = get();
                return t;
            } finally {
                latch.countDown();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        long l = System.currentTimeMillis();
        CancelTaskManager futureProvider = new CancelTaskManager(2);
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        try {
            futureProvider.addTask(() -> {
                System.out.println("1....start");
                try {
                    TimeUnit.SECONDS.sleep(4);
                } catch (InterruptedException e) {
                    System.out.println("1....on error");
                    Thread.currentThread().interrupt();
                }
                System.out.println("1....end");
                System.out.println(Thread.currentThread().getName() + " 耗时: " + (System.currentTimeMillis() - l) / 1000);
                return "success";
            },executorService).addTask(() -> {
                System.out.println("2....start");
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    System.out.println("2....on error");
                    Thread.currentThread().interrupt();
                }
                System.out.println("2....end");
                System.out.println(Thread.currentThread().getName() + " 耗时: " + (System.currentTimeMillis() - l) / 1000);
                return 1;
            },executorService).execute(6L, TimeUnit.SECONDS, list -> {
                System.out.println("正常结束" + list);
                System.out.println(Thread.currentThread().getName() + " 耗时: " + (System.currentTimeMillis() - l) / 1000);
            });
        } catch (Exception e) {
            System.out.println("main.....error" + e.getMessage());
            System.out.println("main 耗时: " + (System.currentTimeMillis() - l) / 1000);
        }
        TimeUnit.SECONDS.sleep(15);
        executorService.shutdownNow();

    }


}

结果:

1....start
2....start
2....end
pool-1-thread-2 耗时: 3
1....end
pool-1-thread-1 耗时: 4
正常结束[success, 1]
main 耗时: 4

没有问题,子任务在6秒内都成功返回了

将第一个任务睡眠时间设置成 15秒

System.out.println("1....start");
try {
    TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
    System.out.println("1....on error");
    Thread.currentThread().interrupt();
}
System.out.println("1....end");
System.out.println(Thread.currentThread().getName() + " 耗时: " + (System.currentTimeMillis() - l) / 1000);
return "success";

结果

1....start
2....start
2....end
pool-1-thread-2 耗时: 3
cancel 1681595665
1....on error
1....end
pool-1-thread-1 耗时: 6

可以发现,子任务1 虽然睡眠了15秒,但是由于主线程设置了6秒超时,所以在6秒的时候就被中断取消了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值