Explain Codes LogoExplain Codes Logo

How to set a Timer in Java?

java
executor-service
callable
future
Anton ShumikhinbyAnton Shumikhin·Feb 21, 2025
TLDR

The Timer and TimerTask classes are suitable for straightforward periodic tasks:

Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println("All work and no play makes Jack a dull developer!"); // The Shining, dev style. } }, 0, 1000); // Start ASAP, repeat every 1000ms (1 second).

Invoke the run method of TimerTask every second without delay. Bring it to a halt with cancel when necessary.

Welcome the Executors

For handling complex tasks like database connections, using ExecutorService and Future introduces more control and reliability:

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); Callable<String> task = () -> { // Mystery: Why do developers don't talk to DB directly? They're afraid to drop a table. return "Successful connection"; }; Future<String> future = executor.schedule(task, 2, TimeUnit.MINUTES); try { System.out.println(future.get(120, TimeUnit.SECONDS)); // Waits 2 mins, longer than my coffee break. } catch (InterruptedException | ExecutionException | TimeoutException e) { // If anything goes wrong, we panic... properly! e.printStackTrace(); } finally { // Don't leave your threads running, *they need some sleep too*. executor.shutdown(); }

Prepared for rain: Handling timeouts and exceptions

As we sail in the sea of code, it's crucial to be ready for the storms of timeouts and exceptions:

Future<String> future = executor.schedule(task, 1, TimeUnit.SECONDS); try { System.out.println(future.get(1, TimeUnit.SECONDS)); // Wait for 1s, done by the time you blink. } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); // Log and scream! } catch (TimeoutException e) { e.printStackTrace(); // Log and scream, but in a hurry! } finally { executor.shutdown(); // Always close the door when you leave. }

The scheduler ultimatum

Grasping the difference between scheduling methods can save your task:

  • scheduleAtFixedRate: Consistent frequency, regardless of execution time.
  • schedule: Ensures delay between task executions, considering execution time.

Make your pick based on whether you need a regular interval or a fixed delay.

Handling DB tasks with Callable and FutureTask

When you're dealing with data connectivity tasks, Callable and FutureTask offer more control and clarity:

Callable<Boolean> callable = () -> { boolean successful = db.connect(); // Are we there yet? return successful; }; FutureTask<Boolean> task = new FutureTask<>(callable); executor.execute(task); try { Boolean result = task.get(2, TimeUnit.MINUTES); // Wait! The DB is shy. Give it 2 minutes. if (result) { System.out.println("Database is friendly!"); } } catch (TimeoutException e) { System.out.println("The DB ghosted us. Time out!"); // Rejected by DB. Ouch! } finally { executor.shutdownNow(); }

Always cater to InterruptedException and ExecutionException. Moreover, avoid infinite task runs because resources aren't infinite.

Android UI tasks? We got this

In an Android world, the UI-related tasks have to be on the main thread:

Activity activity = ... // Your cool activity timer.schedule(new TimerTask() { @Override public void run() { activity.runOnUiThread(new Runnable() { @Override public void run() { // The UI magician is here! } }); } }, 0, 1000);

This makes sure you avoid the infamous CalledFromWrongThreadException. Just remember, Thread carefully here.