java - 如何在一天后自动终止计时器?

标签 java multithreading timer executorservice

我正在尝试构建多个计时器并为每个计时器安排独立的任务。我有一个用于保存 Timer 及其变量的构造函数。我会为每个计时器设置不同的生命周期,例如一个计时器将在 1 天后终止,而其他计时器将永远运行。我有一个想法在这些计时器之上构建另一个计时器并控制它们的状态,但我担心该程序会变得困惑且庞大。还有其他方法吗?谢谢

代码:

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

触发计时器:

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.setLifespan('24'); //24 hour
        timerVariable.setAliveTime(30); // seconds
        tmpTimer.start(timerVariable); //timerVariable is a value object
      }
    }
}

定时器的构造函数:

import java.time.LocalDateTime;
import java.util.concurrent.*;
import java.util.Date;

public class TimerConstructor{
    private static varObjectvo timerVO = null;
  
    public void start(varObjectvo obj) {
        timerVO = obj;
        executor  = Executors.newSingleThreadScheduledExecutor();
        startTime = LocalDateTime.now();
        endTime = startTime.plusSeconds(obj.getAliveTime());

        timer.scheduleAtFixedRate(task, new Date(), 10000);

        while (true) {
            if (endTime.getHour()==LocalDateTime.now().getHour() && 
                endTime.getMinute()==LocalDateTime.now().getMinute() &&
                endTime.getSecond()==LocalDateTime.now().getSecond()) {
                scheduleFuture.cancel(true);
                executor.shutdown();
                System.out.println("Cancelling " + scheduleFuture.toString());
            
                break;
            }
        }    

    }
  
    private class TimerChecker extends TimerTask {
      public void run() {
        System.out.println("It is timer " + timerVO.getIndex());
      }
    }
  }

值对象类:

public class varObjectvo{
    private Integer index;
    private Integer lifespan;
 
    public void setIndex(Integer i){ 
        this.index = i;
    }
    public Integer getIndex(){ 
        return this.index;
    }
    
    public void setLifespan(Integer i){ 
        this.lifespan= i;
    };
    public Integer getLifespan(){ 
        return this.lifespan;
    };
  }

最佳答案

执行者框架

I am trying to build multiple Timers

如果您阅读 Timer 的 Javadoc & TimerTask,您将看到说明这些类现在已成为遗留类的注释。

Is there any other method for this?

是的。

TimerTimerTask 类很久以前就被 Java 5 中添加的 Executors 框架所取代。请参阅 tutorial by Oracle .

将您的任务定义为 Runnable或一个可调用。将您的任务实例提交到 ExecutorService .

scheduled independent tasks for each of them.

一个执行器服务可以处理多个任务。

一个scheduled executor service可以在指定的时间后运行每个提交的任务,也可以重复运行。

keep other run forever

将您的任务提交给计划的执行程序服务,以使其重复且无限期地运行。

one timer will be terminated after 1 day

让您的任务自行重新安排直到到期。

编写您的任务类,使其保存对计划执行程序服务的引用,记住它首次启动的时间,并为下一次运行重新安排自身,除非指定的时间限制已过。

I have a thought to build another a timer on top of those timers

没必要。您将重新发明预定的执行器服务。

搜索 Stack Overflow 以了解更多信息。所有这些都已经被多次报道过。

示例代码

这里有一些粗略的代码可以帮助您继续。

定义一个告知当前时间的任务。我们会看到它运行一次,也会看到它无限期地运行。

public class TellTime implements Runnable
{

    @Override
    public void run ( )
    {
        System.out.println( "Current moment: " + Instant.now() );
    }
}

还有一个执行倒计时的任务。我们将在指定的时间限制内运行它。请注意此类的实例如何保存对计划执行程序服务的引用,然后使用它来计划自己的下一次执行。

public class Countdown implements Runnable
{
    private final Duration countingDown;
    private final Duration sleep;
    private final ScheduledExecutorService scheduledExecutorService;
    private final Instant start;

    public Countdown ( Duration countingDown , Duration sleep , ScheduledExecutorService scheduledExecutorService )
    {
        this.countingDown = countingDown;
        this.sleep = sleep;
        this.scheduledExecutorService = scheduledExecutorService;
        this.start = Instant.now();
    }

    @Override
    public void run ( )
    {
        Instant end = this.start.plus( this.countingDown );
        Duration remaining = Duration.between( Instant.now() , end );
        if ( remaining.isNegative() )
        {
            Instant now = Instant.now();
            Duration elapsed = Duration.between( this.start , now );
            System.out.println( "Countdown " + this.countingDown + " expired at " + now + ". Elapsed: " + elapsed + ". " );
        }
        else
        {
            System.out.println( "Countdown remaining: " + remaining );
            this.scheduledExecutorService.schedule( this , this.sleep.toNanos() , TimeUnit.NANOSECONDS );
        }
    }
}

以及一个运行这些任务的应用程序。

public class App
{
    private ScheduledExecutorService ses;

    public static void main ( String[] args )
    {
        App app = new App();
        app.demo();
    }

    private void demo ( )
    {
        ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();

        // Run once.
        ses.schedule( new TellTime() , 5 , TimeUnit.SECONDS );

        // Run repeatedly, indefinitely.
        ses.scheduleAtFixedRate( new TellTime() , 20 , 10 , TimeUnit.SECONDS );

        // Run for a limited time.
        Countdown countdown = new Countdown( Duration.ofHours( 1 ) , Duration.ofMinutes( 1 ) , ses );
        ses.schedule( countdown , 1 , TimeUnit.MINUTES );

        // Let the app run until the user wants to stop.
        try (
                Scanner scanner = new Scanner( System.in ) ;
        )
        {
            System.out.println( "Type anything to end this app." );
            String ignoreThis = scanner.nextLine();
        }
        this.shutdownScheduledExecutorService();
    }

    private void shutdownScheduledExecutorService ( )
    {
        // Eventually shutdown your executor service.
        // Otherwise, its backing thread pool may continue indefinitely, like a zombie. 🧟‍
        // This code is a slightly modified copy taken from the Javadoc of `ExecutorService` class in Java 17.
        if ( Objects.isNull( this.ses ) ) { return; }
        this.ses.shutdown(); // Disable new tasks from being submitted
        try
        {
            // Wait a while for existing tasks to terminate
            if ( ! this.ses.awaitTermination( 60 , TimeUnit.SECONDS ) )
            {
                this.ses.shutdownNow(); // Cancel currently executing tasks
                // Wait a while for tasks to respond to being cancelled
                if ( ! this.ses.awaitTermination( 60 , TimeUnit.SECONDS ) )
                { System.err.println( "Pool did not terminate" ); }
            }
        }
        catch ( InterruptedException ex )
        {
            // (Re-)Cancel if current thread also interrupted
            this.ses.shutdownNow();
            // Preserve interrupt status
            Thread.currentThread().interrupt();
        }
    }
}

运行时。

Type anything to end this app.
Current moment: 2022-06-20T07:26:23.732838Z
Current moment: 2022-06-20T07:26:38.732350Z
Current moment: 2022-06-20T07:26:48.731164Z
Current moment: 2022-06-20T07:26:58.727703Z
Current moment: 2022-06-20T07:27:08.730252Z
Current moment: 2022-06-20T07:27:18.727893Z
Countdown remaining: PT58M59.998505S
Current moment: 2022-06-20T07:27:28.730477Z
Current moment: 2022-06-20T07:27:38.727705Z
…

警告:跨线程打印到 System.out 并不总是按时间顺序显示。始终包含时间戳,并仔细研究以验证事件的顺序。

关于java - 如何在一天后自动终止计时器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72674682/

相关文章:

java - 我该如何做才能让方法等待执行器运行?

C++ 类 - 每 N 毫秒递增和递减属性

java - @AfterClass 在 cucumber 脚本中不起作用

java - 大于 $75 的正则表达式

java - Solr 。更新文档多值字段(无重复值),无需已提交

java - 为什么在字段变量上同步并在同步块(synchronized block)内递增它会导致打印乱序?

c - 服务器程序卡在接受函数处

java - 为什么Java的HashTable是同步的?

matlab - 如何知道Matlab中系统命令执行过程中耗时?

java - 尝试运行多个线程时,空指针异常导致强制关闭