Leepoint Java Reference Notes on the Java language and its standard library.

Timers

Three classes, two of them called Timer, and the difference matters.

For a Swing interface

Timer timer = new javax.swing.Timer(1000, e -> label.setText(now()));
timer.start();

javax.swing.Timer fires on the Event Dispatch Thread, so the listener may touch components directly. That is exactly what you want for a clock, an animation or a periodic refresh.

The corollary: the listener must be quick. It runs on the thread that paints the interface, so slow work there freezes the window.

For background work

ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(this::poll, 0, 5, TimeUnit.SECONDS);

Runs on its own thread. Preferred over java.util.Timer, which is the older class and has two flaws worth knowing: it uses a single thread for all tasks, so one long task delays the rest, and an uncaught exception in a task kills the timer thread and silently stops everything else scheduled on it.

ScheduledExecutorService survives a failing task. Shut it down when you are finished:

exec.shutdown();

Otherwise its thread keeps the JVM alive.

Fixed rate or fixed delay

scheduleAtFixedRate(task, 0, 5, SECONDS);    // every 5s from the start
scheduleWithFixedDelay(task, 0, 5, SECONDS); // 5s after each finishes

Fixed rate tries to keep to a schedule and will run tasks back to back to catch up if one overruns. Fixed delay always leaves the gap. For polling something, fixed delay is usually what you want; for a clock, fixed rate.

If it must touch the UI

A background timer’s task runs off the EDT, so it may not touch components:

exec.scheduleWithFixedDelay(() -> {
    var data = fetch();
    SwingUtilities.invokeLater(() -> table.setModel(new Model(data)));
}, 0, 30, SECONDS);

Fetch on the background thread, update inside invokeLater. Skipping the marshal produces intermittent painting faults that are very hard to reproduce.

Accuracy

None of these are real-time. A one-second timer fires approximately every second; scheduling delay, garbage collection and system load all add jitter. For animation, do not accumulate ticks to track elapsed time — read the clock:

long elapsed = System.nanoTime() - start;

Counting ticks drifts. Reading the clock does not.

Cancelling

swingTimer.stop();
scheduledFuture.cancel(false);

A timer nobody cancels keeps its target object reachable, which is a common and quiet memory leak in long-running applications.