V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mengjisang
V2EX  ›  Java

求助 CompletableFuture 怎么取消其任务

  •  
  •   mengjisang · 246 天前 · 1808 次点击
    这是一个创建于 246 天前的主题,其中的信息可能已经有所发展或是发生改变。

    查询到 cancel 方法其原型为

        /* ------------- Control and status methods -------------- */
    
        /**
         * If not already completed, completes this CompletableFuture with
         * a {@link CancellationException}. Dependent CompletableFutures
         * that have not already completed will also complete
         * exceptionally, with a {@link CompletionException} caused by
         * this {@code CancellationException}.
         *
         * @param mayInterruptIfRunning this value has no effect in this
         * implementation because interrupts are not used to control
         * processing.
         *
         * @return {@code true} if this task is now cancelled
         */
        public boolean cancel(boolean mayInterruptIfRunning) {
            boolean cancelled = (result == null) &&
                internalComplete(new AltResult(new CancellationException()));
            postComplete();
            return cancelled || isCancelled();
        }
    

    mayInterruptIfRunning 参数实际并没有被用到,取消操作实际是软取消,并不会直接从线程池中进行取消操作, 实际测试发现 cancel 确实有问题,没有按照想象中快速取消超时任务,最终会导致线程池阻塞,不知道该怎么办

    9 条回复    2024-04-16 17:03:09 +08:00
    BBCCBB
        1
    BBCCBB  
       246 天前
    线程已经开始执行, 又没有可以被 interupt 的操作, 是取消不了的. 取消只是一个信号通知, 要代码里有响应才行.

    线程跑到一半, 也不能直接把线程 destory 了不是?
    mengjisang
        2
    mengjisang  
    OP
       246 天前
    @BBCCBB 大概明白了,这个 cancel 方法,似乎就是设置了一下内部状态,然后抛出 CancellationException 异常
    xiaofan2
        3
    xiaofan2  
       246 天前
    取消都是通知操作 无论是线程池还是其他的业务场景 真正要不要获取这种信号以及如何处理应该由业务逻辑处理 你看看 InterruptException
    inter12
        4
    inter12  
       246 天前
    1.把线程放到一个上下文中
    2.在线程逻辑里面放置一个钩子
    3.触发这个钩子
    guyeu
        5
    guyeu  
       246 天前   ❤️ 1
    你的目的是不要线程池阻塞?这里的阻塞不是一个很清晰的表述,假如它是指避免一个任务长期占用线程:
    1. 对于计算密集型任务,唯一实际可用的办法是在逻辑里去检查线程的内部状态然后按照业务去处理(早期版本可以用一个叫`Thread.stop`的方法来暴力停止,但这不是一个生产可用的选项);
    2. 对于 IO 密集型任务,合理的实现都会响应`interrupt`信号,因此`cancel`方法就足够了。

    实际上,更常见的需求是避免任务堆积导致内存压力,这种情况下:
    1. 限制阻塞队列的长度,并设计合理的拒绝策略;
    2. 解决资源瓶颈,缺 CPU 就加 CPU ,缺消费者就增加消费者节点。
    wolfie
        6
    wolfie  
       246 天前
    interrupt 是多线程通信的一个标记,没开始的任务可以终止。
    建议贴出原始需求。
    boywang004
        7
    boywang004  
       246 天前
    Java 之所以是比较安全的语言,就是这样设计的……你可以让一个线程「去死」,但是人家愿意不愿意死,甚至愿意不愿意理你,都是人家的自由。我见过太多开发者不正确的处理 InterruptedException 了。这样的代码如果你尝试 cancel(true),就坐等杯具了。
    Karte
        8
    Karte  
       246 天前
    Interrupted 会告知线程当前是否被中断, 需要在 run() 方法中判断. 如果没有判断这个通知就是无效的, 线程依旧会执行. 还有如果收到了 interrupted 中断, 建议手动再次执行 `Thread.currentThread().interrupt();`, 这样可以让上层感知到线程被中断了.
    mengjisang
        9
    mengjisang  
    OP
       245 天前
    结论就是,CompletableFuture 能中断那些没有被放入线程池执行的任务,已经执行的会抛出中断信号,但是线程内的任务何时退出则取决于任务执行情况和线程池的调度。

    因为,最后我用了 ReentrantLock 来保证每次只有一个线程去执行定时任务,只有一个线程占用线程池资源,另外如果要外部判断线程池的状态,则需要再启一个线程去定时轮询
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5279 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 07:03 · PVG 15:03 · LAX 23:03 · JFK 02:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.