ScheduledExecutorService with dating format added to ActionListener

本小妞迷上赌 提交于 2021-02-10 18:34:49

问题


I understand that in Java, it is possible to use a ScheduledExecutorService to perform a specific task after a certain delay. This post shows how to execute the task at a specific date, but not with a SimpleDateFormat . For example, I have a format initialized like below:

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

Additionally, I want to execute a particular task declared under an else if statement in an ActionListener , such as below:

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

            }
        });

How could I initialize a ScheduledExecutorService that is executed within and/or with an else if statement at a certain date, preferably with a SimpleDateFormat ?


回答1:


Establish the executor service earlier

How could I initialize a ScheduledExecutorService that is executed within and/or with an else if

You don’t.

Do not initialize your executor service at the point where you need it.

You instantiate your scheduled executor service elsewhere, earlier, keeping a reference in a named variable. Call upon that executor service object as needed, later.

That executor service can be called on to run other kinds of tasks in other parts of your app. The executor service need not be tied to only a single kind of task.

Important You must keep a reference to that executor service so that it’s backing thread pool can be gracefully shut down at some point. Otherwise the thread pool may continue running after its originating app has ended.

Generally, I suggest this approach.

  • When the app launches, establish your executor service. Keep a reference to be accessed later via your choice of a global variable. Perhaps a Singleton, or a Service Locator, or dependency injection such as passing to a constructor.
  • During your app’s run, locate that existing executor service. Submit your task to be run.
  • When the app is ending, locate that existing executor service. Call its shut-down method to end its backing thread pool.

Search Stack Overflow. This topic has been covered many times. You will find example code and further discussion.

Example code

Use the Executors utility class to instantiate an executor service.

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor() ; 

Store that ses reference somewhere in your app.

Calculate the amount of time to wait, as shown in the 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() ;

        }
    }
);

When your app is quitting, shut down that scheduled executor service.

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



回答2:


java.time

Do use java.time, the modern Java date and time API for your date and time work. The modern class to use instead of the old SimpleDateFormat is DateTimeFormatter.

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

Edit: as Basil Bourque said in the comment, also declare your executor service somewhere where you can close it when you no more need it. For example:

static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

Now in your action listener (or any other place you may like), you may do:

        } 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);
        }

Remember to shut down the executor to release resources by calling

    executor.shutdown();

Or if you want to cancel already scheduled tasks, use shutdownNow() instead.

I have put pretty random values for desired time and time zone, so please insert your values instead. If you want the time zone setting of your JVM, ZoneId.systemDefault() is an option.

Among many other advantages java.time has better support for calculating the length of the time interval from now until the desired scheduled time. If you require better than second accuracy, use milliseconds, microseconds or even nanoseconds instead, it goes in a quite similar fashion (since your string seems to have only minute precision, I didn’t think it was necessary).

The SimpleDateFormat that you mentioned is a notorious troublemaker of a class, you will never ever prefer to use it. Fortunately it is also long outdated.

Link

Oracle tutorial: Date Time explaining how to use java.time.



来源:https://stackoverflow.com/questions/60945333/scheduledexecutorservice-with-dating-format-added-to-actionlistener

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!