ScheduledExecutorService只运行一次

11

我希望在启动WebService后运行一个进程,然后每隔30分钟左右运行一次(现在为了测试它是否工作,我使用较小的延迟时间),但是我的进程永远不会超过一次。我做错了什么?

这是我的代码:

@WebListener
public class SchedulerService implements ServletContextListener{

    @Autowired
    UpdateSubscriberService updateSubscriberService;

    ScheduledExecutorService scheduledExecService;

    public SchedulerService(){
        scheduledExecService = Executors.newSingleThreadScheduledExecutor();
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        scheduledExecService.shutdown();
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        scheduledExecService.scheduleWithFixedDelay(new Runnable(){
            @Override
            public void run() {
                Date date = new Date(System.currentTimeMillis());
                System.out.println("Running scheduled update check " + date.toString());
                updateSubscriberService.checkForUpdates();
            }
        }, 60, 30, TimeUnit.SECONDS);
    }
}

3
你确定run()方法会返回吗? - Warrior
2个回答

25

请看我在类似问题上的更长 答案

try catch包装run代码

猜测:可能抛出了异常。如果ScheduledExecutorService遇到异常,它会静默停止,不执行任何进一步的计划工作。

run方法的代码应始终被try-catch包围以处理和吸收任何抛出的异常。

顺便提一下,可怕的Date类已被现代的java.time类替换。具体来说,被Instant取代。

 @Override
 public void run() {
    try {  // Let no Exception reach the ScheduledExecutorService.
        Instant instant = Instant.now() ;
        System.out.println("Running scheduled update check " + instant );
        updateSubscriberService.checkForUpdates();
    } catch ( Exception e ) {
        System.out.println( "ERROR - unexpected exception" );
    }
}

桩定run方法

迈出第一步。从一个什么也不做,只有System.out.printlnrun方法开始。


当我将其更改为仅打印语句时,它执行了多次,正如应该的那样,因此至少我现在知道问题不在调度代码中! - MMAdams
你好 Basil,如果我想使用ScheduledExecutorService只运行一次怎么办?为什么我问这个问题,因为我有两个类,其中一个类必须被安排,而另一个类只能运行一次。 - Suresh
非常奇怪,我的代码没有抛出异常,但我仍然需要这样做! - Dan Rayson
@BasilBourque 嗯,我在catch中设置了一个断点,以查看是否确实抛出了异常,但我的具体代码并没有。非常奇怪,所以我不会假装理解它lol。 - Dan Rayson
1
"采取小步骤",这是一个非常好的建议,帮助我解决了问题,非常感谢。 - jack jin
显示剩余4条评论

1

如果你有这样的情况,需要让代码每隔一段时间运行一次,即使上一次运行还没有完成(如果管理不当会非常危险),你可以在计时器内部启动一个不同的线程来运行你的进程。以下是示例代码。

ScheduledExecutorService scheduledExecService = newSingleThreadScheduledExecutor();
scheduledExecService.scheduleWithFixedDelay(new Runnable()
{
    @Override
    public void run()
    {
        // This should be in a try-catch because any error here
        // will stop the recurrence
        try
        {
            // The timer will only repeat if the last run is finished. So
            // we put each new process in a different thread than the timer
            // itself, so the last timer call "finishes" as soon as the process
            // leaves the timer's thread.
            Thread t = new Thread(new Runnable()
            {
                public void run()
                {
                    try
                    {
                        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                        MyProcessThatShouldRunEverySoManySecondsNoMatterWhat();
                    }
                    catch (Exception erTimerThread)
                    {
                        Log.e("Error", erTimerThread.toString());
                    }
                }
            });
            t.setPriority(2);
            t.start();
        }
        catch (Exception erTimer)
        {
            Log.e("Error", erTimer.toString());
        }
    }
}, 0, 60, java.util.concurrent.TimeUnit.SECONDS);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接