Java运行事件在将来的特定时间

时间:2018-10-31 10:06:07

标签: java mysql web-services web jersey

我正在设计一个使用Jersey的Java Web应用程序,其中在mysql db中有一个日期时间字段“ future_time”。我也在同一表中将状态字段设置为待处理。 如果当前时间> = future_time,我想将状态字段更新为在db中完成。就像我要安排一个活动。

第二,如果current_ time

当前,每当我获取状态字段时,我都会检查状态字段是否未决,如果未完成,那么我将检查future_time <= current_time,如果是,则将db中的状态字段更新为已完成。但这是有问题的。当我获取状态字段时,这只会更新状态字段。因此,如果我在很长一段时间(future_time之后)之后获取状态字段,那么它将在那一刻进行更新,将错误的记录保存在db中。

有人能建议我实现这一目标的更好方法吗?

2 个答案:

答案 0 :(得分:0)

您可以使用ScheduledExecutorService在特定的时间间隔,固定的延迟时间或特定的时间点安排任务。

您可以像这样创建ScheduledExecutorService

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

然后使用该服务安排作业,例如:

//scheduling at fixed time.
Future<String> resultFuture = executorService.schedule(new Callable<String>() {
    @Override
    public String call() throws Exception
    {
        //your code;
    }
}, 1, TimeUnit.SECONDS);

//scheduling at fixed intervals.
executorService.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run()
    {
        //your code
    }
}, 100, 450, TimeUnit.MILLISECONDS);

//scheduling at fixed delays.
executorService.scheduleWithFixedDelay(new Runnable() {
    @Override
    public void run()
    {
        //your code
    }
}, 100, 150, TimeUnit.MILLISECONDS);

您还可以使用Java Timer Utility计划将来的任务,但是Java规范说更喜欢ScheduledExecutorService。以下是使用Timer计划作业的示例代码。

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Timer;
import java.util.TimerTask;


/**
 * An example for Java Timer Utility.
 *
 * @author Karan Khanna.
 */
public class TimerExample
{

    public static void scheduleTaskForFuture(final Date date)
    {
        Timer timer = new Timer("Timer");
        TimerTask task = new TimerTask()
        {
            public void run()
            {

                System.out.println(
                    String
                        .format("Task performed on: %s and Thread's name: %s", date, Thread.currentThread().getName()));

                timer.cancel();
            }
        };
        timer.schedule(task, date);
    }



    public static void main(final String[] args)
    {
        Calendar calendar = new GregorianCalendar();
        calendar.add(Calendar.MINUTE, 1);
        TimerExample.scheduleTaskForFuture(calendar.getTime());
    }
}

您可以更多地探索该实用程序以安排重复的任务。 另外,一旦完成所需的工作,别忘了取消任务。

您也可以为此尝试其他框架,例如Quartz和Spring调度。

答案 1 :(得分:0)

计算直到截止日期为止的经过时间

在JDBC 4.2和更高版本中,使用现代的 java.time 类检索日期时间。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class );  // Likely to be a UTC value.

获取当前时刻。

OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ) ;

计算经过的时间。

Duration d = Duration.between( now , odt ) ;

计划事件

使用现代的Executor framework而不是传统的Timer类。在ServletJakarta.ee (Java EE)环境中尤其如此。

定义您的执行者,特别是ScheduledExecutorService。我们只需一个线程即可完成此任务。

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor()

让执行者等待一段时间,然后运行您的代码以检查数据库中的状态。

myExecutorService.schedule(           // Tell the executor what you want to run, and when you want it run on your behalf in a background thread.
    new Runnable() { … } ,            // Define task to be executed as a `Runnable`.
    d.toSeconds() ,                   // Amount of time to wait until execution. Use self-documenting code rather than a “magic number” such as `86400000`. 
    TimeUnit.SECONDS                  // Specify the granularity of time used in previous pair of arguments.
)                                     // Returns a `ScheduledFuture` which you may want to cache.

(可选)您可以捕获此schedule语句返回的ScheduledFuture。然后,您可以监视完成状态。

在您的Runnable中,从数据库中检索当前状态记录。如果有必要,请安排另一个执行时间,并使用新的当前时刻重新计算等待时间。

Servlet Web容器

对于没有完整web container堆栈的Servlet Jakarta.ee(例如 Tomcat Jetty ),适用以上讨论。

此外,您将需要编写一个实现ServletContextListener接口的类,您可以在其中设置和拆除执行程序服务。您需要适当地关闭执行程序服务,以使其后台线程在您的Web应用程序关闭后很长一段时间内不会继续正常运行。

Jakarta EE

如果使用成熟的Jakarta.ee堆栈(例如Glassfish),则这项工作会容易得多。

上面显示的执行程序服务可以自动化,代表您执行设置和拆卸。使用JSR 236: Concurrency Utilities for JavaTM EE中定义的并发实用程序。这已经被覆盖了很多次,因此请搜索Stack Overflow以获取更多信息。


关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore