The Answer by iota correctly solved your direct problem. But looking at the bigger picture, you are using obsolete classes. The modern approach with executor service and runnable is easier and simpler.
Avoid the legacy classes
The Timer
and TimerTask
classes were supplanted with the executor service framework in Java 5 and later.
Likewise, the terrible Date
class was supplanted years ago by the modern java.time classes defined in JSR 310. Replaced specifically by java.time.Instant
.
Environment
class
Let's define your Environment
class. This class monitors two pieces of equipment that sample the environment, and reports the current readings when asked via its report
method.
package work.basil.example;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
public class Environment
{
private SI7021 si7021 = new Environment.SI7021();
private SGP30 sgp30 = new Environment.SGP30();
public void report ( )
{
System.out.println( "------------| Environment Report at " + Instant.now().truncatedTo( ChronoUnit.SECONDS ) + " |------------------------" );
System.out.printf( "Humidity = %.0f Temperature = %.2f \n" , si7021.getHumidity() , si7021.getTemperature() );
System.out.printf( "eCO2 = %d ppm TVOC = %d \n" , sgp30.getECO2() , sgp30.getTVOC() );
}
class SI7021
{
public float getHumidity ( )
{
return ThreadLocalRandom.current().nextFloat() * 100;
}
public float getTemperature ( )
{
return ThreadLocalRandom.current().nextFloat() * 100;
}
}
class SGP30
{
public int getECO2 ( )
{
return ThreadLocalRandom.current().nextInt( 1 , 100 );
}
public int getTVOC ( )
{
return ThreadLocalRandom.current().nextInt( 1 , 100 );
}
}
}
Runnable
Define your task as a Runnable
object having a run
method.
Using lambda syntax, that would simply be:
Runnable task = ( ) -> environment.report() ;
Or use a method reference.
Runnable task = environment :: report ;
Or, if you are not comfortable with the modern syntax, use an anonymous class.
Runnable task = new Runnable()
{
@Override
public void run ( )
{environment.report();}
};
Scheduled executor service
The ScheduledExecutorService
interface repeatedly runs a task, a Runnable
. You have a choice of scheduleAtFixedRate
or scheduleWithFixedDelay
, so read the Javadoc to decide which kind of cadence fits your needs.
Be sure to gracefully shutdown your executor service. Otherwise, its backing thread pool may run indefinitely, like a zombie ♂️. We use a try-finally
to make sure the executor service is shutdown. FYI, in the future when Project Loom arrives, ExecutorService
will be AutoCloseable
. We will then be able to use try-with-resources syntax for simpler approach to do the shutdown.
public static void main ( String[] args )
{
System.out.println( "INFO - Starting the scheduled executor service generating Environment reports. " + Instant.now() );
ScheduledExecutorService scheduledExecutorService = null;
try
{
Environment environment = new Environment();
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
Runnable task = environment :: report ;
scheduledExecutorService.scheduleAtFixedRate(
task , // Implements `Runnable`.
0 , // Initial delay.
Duration.ofSeconds( 10 ).toSeconds() , // Period
TimeUnit.SECONDS ) // Unit of time for both delay and period.
;
// … do other stuff
try { Thread.sleep( Duration.ofMinutes( 1 ).toMillis() ); } catch ( InterruptedException e ) { e.printStackTrace(); } // Give our demo a chance to run a while.
System.out.println( "INFO - Will shutdown the scheduled executor service generating Environment reports. " + Instant.now() );
}
finally
{
if ( Objects.nonNull( scheduledExecutorService ) ) { scheduledExecutorService.shutdown(); }
}
}
When run:
INFO - Starting the scheduled executor service generating Environment reports. 2021-01-04T07:46:54.494330Z
------------| Environment Report at 2021-01-04T07:46:54Z |------------------------
Humidity = 95 Temperature = 40.71
eCO2 = 99 ppm TVOC = 1
------------| Environment Report at 2021-01-04T07:47:04Z |------------------------
Humidity = 72 Temperature = 92.15
eCO2 = 25 ppm TVOC = 42
------------| Environment Report at 2021-01-04T07:47:14Z |------------------------
Humidity = 52 Temperature = 94.01
eCO2 = 85 ppm TVOC = 89
------------| Environment Report at 2021-01-04T07:47:24Z |------------------------
Humidity = 80 Temperature = 1.60
eCO2 = 10 ppm TVOC = 78
------------| Environment Report at 2021-01-04T07:47:34Z |------------------------
Humidity = 64 Temperature = 44.97
eCO2 = 50 ppm TVOC = 40
------------| Environment Report at 2021-01-04T07:47:44Z |------------------------
Humidity = 1 Temperature = 31.63
eCO2 = 20 ppm TVOC = 69
------------| Environment Report at 2021-01-04T07:47:54Z |------------------------
Humidity = 30 Temperature = 26.88
eCO2 = 2 ppm TVOC = 86
INFO - Will shutdown the scheduled executor service generating Environment reports. 2021-01-04T07:47:54.516543Z
In real work, surround the innards of your Runnable
with a try-catch to catch any unexpected exceptions (and maybe errors). An exception/error bubbling all the way up to the scheduled executor service causes the service to halt silently, with no further executions performed.