12
new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
       System.out.println("run");
       throw new SomeRandomException();
    }
 }, 1000, 1000);

Output: run (exception is thrown)

Here is the problem: I need a timer task to check for specific conditions in the database (or something else). It worked fine, but sometimes the database(or something else) returns some errors, exception is thrown and the timer crashes, and then no single timer task is executed again. Is there a some Timer implementation which keep working after exception is thrown in run().

I can

new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        try {
            System.out.println("run");
            throw new SomeRandomException();
        } catch (Exception e) {
            System.out.println("dummy catch");
        }
    }
}, 1000, 1000);

but this seems lame.

Other alternative is write my own implementation of Timer class, swallowing exceptions of run method (which seems also not right).

Gray
  • 115,027
  • 24
  • 293
  • 354
Kiril Kirilov
  • 11,167
  • 5
  • 49
  • 74

3 Answers3

9

Use a ScheduledExecutorService. It plays the same role as Timer, but fixes its weaknesses (like the one you're encountering).

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 1
    Unfortunately "If any execution of the task encounters an exception, subsequent executions are suppressed." - from http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ScheduledExecutorService.html#scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit) – Kiril Kirilov Jan 05 '12 at 13:24
  • 1
    Yes, this particular task will stop running, but it doesn't make the executor crash, and other tasks are still scheduled. But I agree that you still have to catch any exception that might happen and must not cause the scheduling of the task to be aborted. You might want to create a CatchAllRunnable reusable class. – JB Nizet Jan 05 '12 at 13:35
0

Using ExecutorService; you can handle both compile time and run exceptions.

Handling exceptions from Java ExecutorService tasks
How is exception handling done in a Callable

ThreadPoolExecutor.java

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}
Community
  • 1
  • 1
Kanagavelu Sugumar
  • 18,766
  • 20
  • 94
  • 101
0

Honestly I don't see any issue with catch and log of exception in timertask run, especialy if you catch all of them and log them right so they not get lost.

fun Timer.schedule(delay: Long = 0, function: () -> Unit): TimerTask {
    val task = object : TimerTask() {
        override fun run() {
            try {
                function()
            } catch (e: Throwable) {
                logError(e)
            }
        }
    }
    schedule(task, delay)
    return task
}

Other option is to catch re-throw and recreate Timer instance maybe ? But I don't know use case for this, on android I would implement it maybe somehow like this:

private var timer = Timer()

schedule(delay: Long = 0, function: () -> Unit): TimerTask {
        val task = object : TimerTask() {
            override fun run() {
                try {
                    function()
                } catch (e: Throwable) {
                    later { timer = Timer() }
                    throw e
                }
            }
        }
        timer.schedule(task, delay)
        return task
    }
Renetik
  • 5,887
  • 1
  • 47
  • 66