代码之家  ›  专栏  ›  技术社区  ›  James McMahon

Java库类来处理“回调”的计划执行?

  •  7
  • James McMahon  · 技术社区  · 16 年前

    我的程序有一个称为调度程序的组件,它允许其他组件在需要回调的时间点上注册。这应该与UnixCron服务非常相似,即,您告诉调度程序“每小时10分钟通知我一次”。

    我意识到Java中没有真正的回调。

    这是我的方法,有没有一个图书馆已经做了这些东西?也可以提出改进建议。

    注册对调度程序的调用传递:

    • 一种包含小时、分钟、秒、年-月、dom、dow的时间规范,其中每项可能未指定,意思是“每小时/分钟执行一次”等(就像crontabs)。
    • 一个包含数据的对象,当调度程序通知调用对象时,这些数据将告诉调用对象要做什么。调度程序不处理此数据,只存储它并在通知时将其传递回。
    • 对调用对象的引用

    在启动时,或者在新的注册请求之后,调度程序将以当前系统时间的日历对象开始,并检查数据库中是否有与此时间点匹配的条目。如果存在,则执行它们并重新启动流程。如果没有,则Calendar对象中的时间将增加一秒钟,然后重新检查entries。重复此操作,直到有一个或多个条目匹配为止。(离散事件模拟)

    然后,调度程序将记住时间戳、睡眠和唤醒,以检查它是否已经存在。如果它恰巧醒了,时间已经过去了,它就会重新开始,同样的,如果时间已经到了,任务已经执行了。


    编辑 :谢谢你给我指石英。不过,我在找小得多的东西。

    8 回复  |  直到 14 年前
        1
  •  4
  •   Community CDub    7 年前

    如果您的需求很简单,请考虑使用 java.util.Timer :

    public class TimerDemo {
    
      public static void main(String[] args) {
        // non-daemon threads prevent termination of VM
        final boolean isDaemon = false;
        Timer timer = new Timer(isDaemon);
    
        final long threeSeconds = 3 * 1000;
        final long delay = 0;
        timer.schedule(new HelloTask(), delay, threeSeconds);
    
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE, 1);
        Date oneMinuteFromNow = calendar.getTime();
    
        timer.schedule(new KillTask(timer), oneMinuteFromNow);
      }
    
      static class HelloTask extends TimerTask {
        @Override
        public void run() {
          System.out.println("Hello");
        }
      }
    
      static class KillTask extends TimerTask {
    
        private final Timer timer;
    
        public KillTask(Timer timer) {
          this.timer = timer;
        }
    
        @Override
        public void run() {
          System.out.println("Cancelling timer");
          timer.cancel();
        }
      }
    
    }
    

    一如既往 noted , the ExecutorService 属于 java.util.concurrent 如果需要,提供更丰富的API。

        2
  •  8
  •   Miserable Variable    16 年前

    查找 Quartz

        3
  •  5
  •   oxbow_lakes    16 年前

    如果您的对象确切地知道它们希望执行的单个时间点,那么您可以使用 java.util.concurrent.ScheduledExecutorService . 然后他们简单地打电话:

    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
    long timeToExecute = ... //read from DB? use CronTrigger?
    long delayToExecution = timeToExecute - System.currentTimeMillis();
    scheduler.schedule(aRunnable, delayToExecution, TimeUnit.MILLISECONDS);
    

    你只需要使用 Quartz 如果您希望调度器本身处理“每5秒执行一次”之类的功能,或者希望围绕错过的执行执行执行执行的复杂行为,或者执行审核跟踪的持久性。

    实际上你可以重复使用石英 CronTrigger 类获取“下一个执行时间”。类是完全独立的,不依赖于从 石英 “语境”。一旦你的下一次执行时间 Date long 你可以使用Java ScheduledExecutorService 如上

        4
  •  4
  •   GaryF    16 年前

    Quartz 是这一地区巨大而明显的发电站,但也有一些可供探索的替代方案。

    Cron4j 是一个相当不错的图书馆,比石英稍微轻一点。它提供了很好的文档,并将执行您想要的操作。

    可能更有趣的是,如果您想使用一个与Java并发库(特别是执行器和调度程序)更好地匹配的库,那么 HA-JDBC 有一个 CronExecutorService 接口,由ITS实现 CronThreadPoolExecutor . 现在,有趣的是,它依赖于Quartz(提供cronExpression类),但我发现这两个类一起工作比单独使用Quartz更好。如果您不需要大的依赖关系,那么很容易从Quartz和HA-JDBC中提取少数类,从而实现这一点。

    因为您想要更小的东西(刚刚注意到您的编辑),所以从Quartz中获取cronExpression和我上面提到的两个ha-jdbc类。就这样。

        5
  •  1
  •   StaxMan    14 年前

    我强烈推荐 cron4j (已经提到)在石英之上,除非你绝对需要一些更先进和复杂的石英特征。cron4j非常关注它应该做什么,有很好的文档,并且不是一个厨房水槽解决方案。

        6
  •  0
  •   Bombe    16 年前

    Quartz scheduler 通常是推荐的。

        7
  •  0
  •   Pat    16 年前

    真不敢相信java.util.timer被选为答案。石英确实是更好的选择。

    Quartz比java.util.timer的一大优势是,使用Quartz,作业可以存储在数据库中。因此,一个JVM可以调度,另一个可以执行。而且(很明显)请求在JVM重新启动后仍然存在。

        8
  •  0
  •   Jeanja    15 年前

    可能更有趣的是,如果您想使用一个与Java并发库(特别是执行器和调度程序)更好地匹配的库,那么HA-JDBC有一个CRONExcel服务接口,由其CrnthRead POLL执行器实现。现在,有趣的是,它依赖于Quartz(提供cronExpression类),但我发现这两个类一起工作比单独使用Quartz更好。如果您不需要大的依赖关系,那么很容易从Quartz和HA-JDBC中提取少数类,从而实现这一点。

    我只是想说我尝试了提取这些类,但它起作用了!我需要这三门课:

    • CronExpression(石英)
    • cronthreadpool执行器(ha jdbc)
    • DaemonthreadFactory(HA JDBC)

    我只需要做这些小调整:

    • 正在从cronthreadpoolExecutor中删除记录器(它是创建的,但从未使用过)
    • 将固定年份从cronTrigger移到cronExpression

    我很激动,因为我没有陷入依赖的纠结中。恭喜同学们!

    它像冠军一样工作。