【问题标题】:How to reschedule a task using a ScheduledExecutorService?如何使用 ScheduledExecutorService 重新安排任务?
【发布时间】:2010-10-12 20:44:20
【问题描述】:

我在 java 文档中看到了这个:ScheduledAtFixedRate,上面写着

如果任务的任何执行 遇到异常,后续 处决被禁止

我不希望这发生在我的应用程序中。即使我看到异常,我也总是希望后续执行发生并继续。如何从ScheduledExecutorService 获得这种行为。

【问题讨论】:

  • 我更喜欢CosmoCode blog中描述的解决方案
  • CosmoCode blog blocks中的解决方案(使用future.get();),与Executors提供的异步执行点相悖.

标签: java


【解决方案1】:

用 try/catch 包围 Callable.call 方法或 Runnable.run 方法...

例如:

public void run()
{
    try
    {
        // ... code
    }
    catch(final IOException ex)
    {
        // handle it
    }
    catch(final RuntimeException ex)
    {
        // handle it
    }
    catch(final Exception ex)
    {
        // handle it
    }
    catch(final Error ex)
    {
        // handle it
    }
    catch(final Throwable ex)
    {
        // handle it
    }
}

请注意,捕获编译器告诉您的内容以外的任何内容(我的示例中的 IOException)并不是一个好主意,但有时,这听起来像是其中之一,如果您妥善处理。

请记住,诸如错误之类的事情非常糟糕 - 虚拟机内存不足等...所以要小心处理它们(这就是为什么我将它们分离到它们自己的处理程序中而不是仅仅执行 catch(final Throwable ex ),仅此而已)。

【讨论】:

  • 请注意,如果您没有在重复的计划任务中捕获 throwable 并且确实发生了 OOME,您将永远不会发现它(除非在 ScheduledFuture 上调用 get() 并记录 ExecutionExceotions
  • 那么......猜你必须...... ick :-)我会验证然后更新我的答案 - thx
  • 是否因为特定线程终止而停止后续执行?如果线程池大小大于 1,这在大多数情况下是正确的,那么为什么 ScheduledExecutorService 实现无法尝试使用不同的线程运行任务?
【解决方案2】:

尝试 jcabi-log 中的 VerboseRunnable 类,它执行 TofuBeer 建议的包装:

import com.jcabi.log.VerboseRunnable;
Runnable runnable = new VerboseRunnable(
  Runnable() {
    public void run() { 
      // do business logic, may Exception occurs
    }
  },
  true // it means that all exceptions will be swallowed and logged
);

现在,当有人调用runnable.run() 时,不会抛出异常。相反,它们被吞下并记录(到 SLF4J)。

【讨论】:

  • 不错,Exceptions 被VerboseRunnable 吞噬了,所以后续的任务会执行。
【解决方案3】:

我遇到了同样的问题。我还尝试了 run() 方法中的 try 块,但它不起作用。

所以到目前为止我做了一些工作:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

public class Test2 {

    static final ExecutorService pool = Executors.newFixedThreadPool(3);

    static final R1 r1 = new R1();
    static final R2 r2 = new R2();

    static final BlockingQueue deadRunnablesQueue = new LinkedBlockingQueue<IdentifiableRunnable>();

    static final Runnable supervisor = new Supervisor(pool, deadRunnablesQueue);

    public static void main(String[] args) {
        pool.submit(r1);
        pool.submit(r2);
        new Thread(supervisor).start();
    }

    static void reSubmit(IdentifiableRunnable r) {
        System.out.println("given to an error, runnable [" + r.getId()
                + "] will be resubmited");
        deadRunnablesQueue.add(r);
    }

    static interface IdentifiableRunnable extends Runnable {
        String getId();
    }

    static class Supervisor implements Runnable {
        private final ExecutorService pool;
        private final BlockingQueue<IdentifiableRunnable> deadRunnablesQueue;

        Supervisor(final ExecutorService pool,
                final BlockingQueue<IdentifiableRunnable> deadRunnablesQueue) {
            this.pool = pool;
            this.deadRunnablesQueue = deadRunnablesQueue;
        }

        @Override
        public void run() {
            while (true) {
                IdentifiableRunnable r = null;
                System.out.println("");
                System.out
                        .println("Supervisor will wait for a new runnable in order to resubmit it...");
                try {
                    System.out.println();
                    r = deadRunnablesQueue.take();
                } catch (InterruptedException e) {
                }
                if (r != null) {
                    System.out.println("Supervisor got runnable [" + r.getId()
                            + "] to resubmit ");
                    pool.submit(r);
                }
            }
        }
    }

    static class R1 implements IdentifiableRunnable {
        private final String id = "R1";
        private long l;

        @Override
        public void run() {
            while (true) {
                System.out.println("R1 " + (l++));
                try {
                    Thread.currentThread().sleep(5000);
                } catch (InterruptedException e) {
                    System.err.println("R1 InterruptedException:");
                }
            }
        }

        public String getId() {
            return id;
        }
    }

    static class R2 implements IdentifiableRunnable {
        private final String id = "R2";
        private long l;

        @Override
        public void run() {
            try {
                while (true) {
                    System.out.println("R2 " + (l++));
                    try {
                        Thread.currentThread().sleep(5000);
                    } catch (InterruptedException e) {
                        System.err.println("R2 InterruptedException:");
                    }
                    if (l == 3) {
                        throw new RuntimeException(
                                "R2 error.. Should I continue to process ? ");
                    }
                }
            } catch (final Throwable t) {
                t.printStackTrace();
                Test2.reSubmit(this);
            }
        }

        public String getId() {
            return id;
        }
    }

}

您可以尝试注释掉 Test2.reSubmit(this) 以查看没有它,R2 将停止工作。

【讨论】:

  • 澄清:实际上 ScheduledExecutorService 确实适用于 run() 方法中的 try 块。上面的例子是基于 ExecutorService 的。
  • 感谢您分享您的代码。这是一个很好的例子,看起来有点复杂。
【解决方案4】:

如果您只想在出现异常后继续执行后续执行,那么这段代码应该可以工作。

 ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();    

 Runnable task = new Runnable() {      
  @Override
  public void run() {
   try{
      System.out.println(new Date() + " printing");
      if(true)
        throw new RuntimeException();

   } catch (Exception exc) {
      System.out.println(" WARN...task will continiue"+ 
            "running even after an Exception has araised");
    }
  }      
};

executor.scheduleAtFixedRate(task, 0, 3, TimeUnit.SECONDS);

如果出现Throwable 而非Exception,您可能不希望执行后续执行。

这是输出

JST 2012 年 11 月 23 日星期五 12:09:38 打印
_WARN...任务将 即使在引发异常后仍继续运行
11 月 23 日星期五 12:09:41 JST 2012 打印
_WARN...任务将继续运行 即使在引发异常后
Fri Nov 23 12:09:44 JST 2012 打印
_WARN...即使在一个 已引发异常
11 月 23 日星期五 12:09:47 JST 2012 打印
_WARN...即使在引发异常后任务仍将继续运行

【讨论】:

    猜你喜欢
    • 2016-12-25
    • 1970-01-01
    • 2016-06-17
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 2021-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多