Search code examples
javamultithreadingtimerjava.util.concurrenttimertask

How to run Timer independently in Java?


I am trying to build multiple Timers and scheduled independent tasks for each of them. I have a constructor for holding a Timer and its variable. Then, I will call them one by one but I found that the variables, passed to the Timer constructor, are overrode by each other. I already initiate each Timer as a new instance but still cannot solve the issue. How can I make sure the timers are run independently?

Code:

public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
        TimerTrigger.INSTANCE.runTimer();
    }
}

To Trigger the timer:

public enum TimerTrigger {
    INSTANCE;

    private TimerTrigger(){}

    public void runTimer(){
      for (int i = 0; i < 3; i++) {
        System.out.println( "Initiaizing Timer " + i );
        TimerConstructor tmpTimer = new TimerConstructor();
        varObjectvo timerVariable = new varObjectvo();
        timerVariable.setIndex(i);
        // timerList.add(tmpTimer); 
        tmpTimer.start(timerVariable); //timerVariable is a value object
      }
    }
}

The Constructor of timer:

import java.util.Timer;
import java.util.TimerTask;
import java.util.Date;
public class TimerConstructor{
    private static varObjectvo timerVO = null;
    Timer timer = null; 
  
    public void start(varObjectvo obj) {
      timer = new Timer("Timer_" + obj.getIndex()); // will be Timer_1/2/3
      timerVO = obj;
      TimerChecker task = new TimerChecker();
      timer.scheduleAtFixedRate(task, new Date(), 10000);
    }
  
    private class TimerChecker extends TimerTask {
      public void run() {
        System.out.println("It is timer " + timerVO.getIndex() + " from: " + timer.toString());
      }
    }
  }

The value object class:

public class varObjectvo{
    private Integer index;
    
    public void setIndex(Integer i){ 
        this.index = i;
    };

    public Integer getIndex(){ 
        return this.index;
    };
  }

Output:

Hello World!
Initiaizing Timer 0
Initiaizing Timer 1
It is timer 0 from:java.util.Timer@6b45c377
It is timer 1 from:java.util.Timer@17481b7c
Initiaizing Timer 2
It is timer 2 from:java.util.Timer@48e94d09
It is timer 2 from:java.util.Timer@17481b7c
It is timer 2 from:java.util.Timer@48e94d09
It is timer 2 from:java.util.Timer@6b45c377

In short, seems the variables in former Timer are being overwritten by the later Timer.


Solution

  • As commented, your main problem seems to be making your variable timerVO static.

    The static keyword means you want only one such value rather than each instance having its own value known by that name. In other words, static is not object-oriented.

    So each time you execute timerVO = obj;, you replace the previously stored value with the current one. You have only a single timerVO in your entire app, because you marked it static. That timerVO can contain only a single value, the value last assigned.

    You said:

    I already initiate each timer as new instance but still cannot solve the issue.

    But… all those timer objects you instantiated share the same single static timerVO object.


    Minor issue: Class names start with an uppercase letter. So public class varObjectvo should be public class VarObjectvo.

    Another minor issue: Naming a method “…Constructor” is confusing. That word has a very specific crucial meaning in Java. A constructor in Java is always named the same as the class name.

    Bigger picture: You are not taking advantage of modern Java. If you read carefully the Javadoc of Timer and TimerTask classes, you’ll see they were supplanted years ago by the Executors framework.

    To use executors, define your tasks as implementing either Runnable or Callable. Then establish a ScheduledExecutorService. Submit instances of your tasks to that service for repeated execution.

    Search Stack Overflow to learn more. Scheduled executor service has been covered many many times already.

    Some rough untested code follows.

    class Counter implements Runnable {
        private final AtomicInteger count = new AtomicInteger( 0 ) ;
    
        void run() { this.count.incrementAndGet() ; }
    
        int getCount() { return this.count.get() ; }
    }
    

    Instantiate.

    Counter countEvery5Seconds = new Counter() ;
    Counter countEvery42Seconds = new Counter() ;
    

    Initialize your scheduled executor service.

    ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor() ; 
    

    Schedule your tasks.

    ScheduledFuture<?> count5 =
       scheduler.scheduleAtFixedRate( countEvery5Seconds, 0, 5, TimeUnit.SECONDS);
    ScheduledFuture<?> count42 =
       scheduler.scheduleAtFixedRate( countEvery42Seconds, 0, 42, TimeUnit.SECONDS);
    

    Be sure to shutdown your executor service. See discussions in many other Answers. See boilerplate code in Javadoc.