zoukankan      html  css  js  c++  java
  • Java定时线程池停止超时任务

    一、背景
    题主最近遇到一个问题,本来通过ScheduledExecutorService线程池定时调度一个任务。奈何不知道为啥跑了2个多月,其中一个任务Hang住了,原本定时的任务则出现了问题。

    关于定时线程池,好多人认为设置好频率(比如1Min),它会按照这个间隔按部就班的工作。但是,如果其中一次调度任务卡住的话,不仅这次调度失败,而且整个线程池也会停在这次调度上。

    我们先从一个例子试着复现下问题:

    public class pool {
    private static class Runner implements Runnable {
    @Override
    public void run() {
    try {
    Thread.sleep(10000);
    System.out.println(new Date());
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    
    public static void main(String[] args) {
    ScheduledExecutorService service 
    = Executors.newScheduledThreadPool(1);
    service.scheduleAtFixedRate(
    new Runner(), 0, 1, TimeUnit.SECONDS);
    }
    }
    

      


    先从Main看,启动一个定时线程池,每隔1S调度一次Runner。看上去,应该是1S调度一次,但是Runner的实际执行时间为10S,那多久会调度一次?答案是10S。
    所以说,这个Runner不管什么原因挂掉了或者Hang住了,那这个定时调度线程池基本就废了。

    二、解决方法
    那我们应该怎么解决这个问题?如果说定时线程池有任务调度的超时策略就完美了,很可惜并没有。
    我们想下在并发编程中,哪种方式有超时策略?
    对,Future有,那我们可以结合Future,提供一种自动停止超时任务的方式,来解决某个任务Hang住的问题。

    我们简单修改下,把sleep逻辑移动到Callable中,并在Runner中使用Future来控制超时。

    public class pool {
    private static class Caller implements Callable<Boolean> {
    @Override
    public Boolean call() {
    try {
    Thread.sleep(10000);
    System.out.println(new Date());
    return true;
    } catch (Exception e) {
    e.printStackTrace();
    }
    return false;
    }
    }
    
    private static class Runner implements Runnable {
    @Override
    public void run() {
    ExecutorService excutor = Executors.newSingleThreadExecutor();
    Future<Boolean> future = excutor.submit(new Caller());
    try {
    future.get(1, TimeUnit.SECONDS);
    } catch (TimeoutException e) {
    System.out.println("timeout");
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    excutor.shutdownNow(); // 强制终止任务
    }
    }
    }
    
    public static void main(String[] args) {
    ScheduledExecutorService service
    = Executors.newScheduledThreadPool(1);
    service.scheduleAtFixedRate(
    new Runner(), 0, 1, TimeUnit.SECONDS);
    }
    }
    

      

    备注:
    - 实现逻辑相当于转移了,把本来应该调度的任务交给了另外一个Future单线程去执行。因为存在超时逻辑,不会影响原有定时线程池的执行。
    - finally是否需要杀死线程池,因人而异。如果不杀死的话,那超时的任务会继续执行。

    题外话:如果你有好的解决方式,欢迎和题主探讨。谢谢。

  • 相关阅读:
    html 6 border border-width border-style border-color CSS三角形
    html 5 marign top right bottom left
    html 布局
    python学习——生成列表并修改其元素
    python学习——读取染色体长度(七:for循环对染色体序列进行反向互补)
    python学习——读取染色体长度(七:读取fasta文件)
    python学习——读取染色体长度(六:读取含有染色体长度的文件)
    python学习——读取染色体长度(五:从命令行输入染色体长度)
    python学习——读取染色体长度(四:获取最长染色体的编号)
    python学习——读取染色体长度(三、用循环或者函数求总长并获取最长染色体长度)
  • 原文地址:https://www.cnblogs.com/yuyu666/p/10069747.html
Copyright © 2011-2022 走看看