【问题标题】:ScheduledExecutorService with dating format added to ActionListener将约会格式添加到 ActionListener 的 ScheduledExecutorService
【发布时间】:2020-03-31 07:25:19
【问题描述】:

我了解在 Java 中,可以使用 ScheduledExecutorService 在一定延迟后执行特定任务。 This 帖子显示了如何在特定日期执行任务,但不是 SimpleDateFormat 。例如,我有一个如下初始化的格式:

dateFormatter = new SimpleDateFormat("MM-dd-yyyy hh:mm aa");

另外,我想执行在 ActionListener 中的 else if 语句下声明的特定任务,如下所示:

foo.addActionListener(e -> {
            if (condition) {

            // some task

            } else if (some other condition) { // what I want to be executed at particular date

            // some other task

            } else {

            // another task

            }
        });

我如何初始化在某个日期在else if 语句内和/或使用else if 语句执行的ScheduledExecutorService,最好使用SimpleDateFormat

【问题讨论】:

  • 我建议你不要使用SimpleDateFormat。这个类是出了名的麻烦和过时。而是使用DateTimeFormatterjava.time, the modern Java date and time API 中的其他类。
  • 您的意思是,在else 部分中,您想安排某件事在某个日期和时间发生吗?抱歉,这个不清楚。另外,在哪个时区?
  • 还有你把搜索引擎放在哪里了? :-) 我相信它可能会带来很多有用的东西。

标签: java date simpledateformat scheduledexecutorservice


【解决方案1】:

提前建立执行器服务

我怎样才能初始化一个ScheduledExecutorService,它在一个 else if 中执行和/或与一个 else if 一起执行

你没有。

不要在你需要的时候初始化你的执行器服务。

您早先在别处实例化您的scheduled executor service,将引用保存在命名变量中。稍后根据需要调用该执行程序服务对象。

可以调用该执行器服务来在应用的其他部分运行其他类型的任务。执行器服务不必只绑定到单一类型的任务。

重要您必须保留对该执行程序服务的引用,以便它的支持线程池可以在某个时候正常关闭。否则线程池可能会在其原始应用程序结束后继续运行

一般来说,我建议采用这种方法。

  • 应用启动时,建立您的执行器服务。保留一个引用,以便稍后通过您选择的全局变量访问。可能是Singleton,或者Service Locator,或者dependency injection,例如passing to a constructor
  • 在您的应用运行期间,找到现有的执行器服务。提交要运行的任务。
  • 应用程序结束时,找到现有的执行器服务。调用其关闭方法以结束其后备线程池。

搜索堆栈溢出。这个话题已经讨论过很多次了。您将找到示例代码和进一步的讨论。

示例代码

使用Executors 实用程序类来实例化一个执行器服务。

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor() ; 

ses 引用存储在您的应用中的某处。

计算等待时间,如correct Answer by Ole V.V.所示

foo.addActionListener(
    e -> {
        if (condition) {

            doSomethingNow() ;

        } else if (some other condition) { 

            long delaySeconds = … ;  // See: https://stackoverflow.com/a/60963540/642706
            ScheduledExecutorService scheduledExecutorService = Objects.requireNonNull​( … ) ;  // Locate the existing scheduled executor service.
            Runnable task = () -> { System.out.println( "Doing something later. " + Instant.now() ) ; };
            scheduledExecutorService.schedule(
                task ,
                delaySeconds ,
                TimeUnit.SECONDS
            );

        } else {

            doSomethingElseNow() ;

        }
    }
);

当您的应用退出时,请关闭该计划的执行器服务。

// In the hook for app shut-down.
ScheduledExecutorService scheduledExecutorService = Objects.requireNonNull​( … ) ;  // Locate the existing scheduled executor service.
scheduledExecutorService.shutdown() ;

【讨论】:

    【解决方案2】:

    java.time

    请使用 java.time,现代 Java 日期和时间 API 来处理日期和时间。代替旧的SimpleDateFormat 使用的现代类是DateTimeFormatter

    static DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern("MM-dd-yyyy hh:mm a", Locale.ENGLISH);
    

    编辑:正如 Basil Bourque 在评论中所说,还要在不再需要时将其关闭的地方声明您的 executor 服务。例如:

    static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    

    现在在您的动作监听器(或您可能喜欢的任何其他地方)中,您可以这样做:

            } else {
                String timeString = "04-01-2020 08:00 AM";
                ZoneId zone = ZoneId.of("America/Curacao");
                ZonedDateTime timeToExecute = LocalDateTime.parse(timeString, formatter)
                        .atZone(zone);
                long delaySeconds = ChronoUnit.SECONDS.between(
                        ZonedDateTime.now(zone), timeToExecute);
                executor.schedule(() -> System.out.println("It’s now " + timeString),
                                delaySeconds, TimeUnit.SECONDS);
            }
    

    记得通过调用关闭executor释放资源

        executor.shutdown();
    

    或者,如果您想取消已安排的任务,请改用shutdownNow()

    我为所需的时间和时区设置了相当随机的值,因此请插入您的值。如果你想要你的 JVM 的时区设置,ZoneId.systemDefault() 是一个选项。

    在许多其他优点中,java.time 更好地支持计算从现在到所需预定时间的时间间隔长度。如果您需要优于秒的精度,请改用毫秒、微秒甚至纳秒,它采用非常相似的方式(因为您的字符串似乎只有分钟精度,我认为没有必要)。

    您提到的SimpleDateFormat 是一个臭名昭著的班级麻烦制造者,您永远不会喜欢使用它。幸好它也早已过时了。

    链接

    Oracle tutorial: Date Time 解释如何使用 java.time。

    【讨论】:

    • 我建议重构此示例代码以将执行程序线程池提取到命名变量。线程池最终需要优雅地关闭,否则它可能会在其应用程序结束后继续运行。我很欣赏你优雅的简洁,但在这里吞下线程池是一个危险的例子。
    • 谢谢@BasilBourque,我终于开始编辑了。一个问题是我们是否要取消已经安排好的任务,或者线程运行直到它们完成是可以的。这就是我们应该调用shutdownNow() 还是只调用shutdown() 的区别,我现在简要解释一下。
    猜你喜欢
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 2021-06-24
    • 2015-02-05
    相关资源
    最近更新 更多