如何使运行在x:00 x:15 x:30和x:45的线程在2:00做不同的事情

时间:2010-05-27 21:24:21

标签: java multithreading timer

我有一个计时器线程,需要在一天中的特定时刻运行,以便使用数据库进行增量复制。现在它在小时,小时15分钟,小时30分钟和小时45分钟之间运行。这是我的代码,它正常工作:

public class TimerRunner implements Runnable {

    private static final Semaphore lock = new Semaphore(1);

    private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    public static void initialize() {
        long delay = getDelay();
        executor.schedule(new TimerRunner(), delay, TimeUnit.SECONDS);
    }

    public static void destroy() {
        executor.shutdownNow();
    }

    private static long getDelay() {
        Calendar now = Calendar.getInstance();
        long p = 15 * 60; // run at 00, 15, 30 and 45 minutes past the hour
        long second = now.get(Calendar.MINUTE) * 60 + now.get(Calendar.SECOND);
        return p - (second % p);
    }

    public static void replicate() {
        if (lock.tryAcquire()) {
            try {
                Thread t = new Thread(new Runnable() {
                    public void run() {
                        try {
                            // here is where the magic happens
                        } finally {
                            lock.release();
                        }
                    }
                });
                t.start();
            } catch (Exception e) {
                lock.release();
            }
        } else {
            throw new IllegalStateException("already running a replicator");
        }
    }

    public void run() {
        try {
            TimerRunner.replicate();
        } finally {
            long delay = getDelay();
            executor.schedule(new TimerRunner(), delay, TimeUnit.SECONDS);
        }
    }

}

当服务器启动并调用TimerRunner.initialize()时,通过调用TimerRunner.destroy()启动此过程。

我已经创建了一个完整的复制过程(而不是增量),我希望在当天的某个时刻运行,比如说凌晨2点。如何改变上面的代码呢?我认为这应该是非常简单的事情,如果它现在是凌晨2点左右,并且已经很长一段时间,因为我完成了复制,然后现在就做,但我不能得到if。

请注意,复制过程有时需要更长时间才能完成。有时超过15分钟,在凌晨2点左右跑步时出现问题。

2 个答案:

答案 0 :(得分:5)

恕我直言,如果它做了不同的事情,它应该不是同一个可运行的。创建一些通用抽象类和两个子类,每个子类都具有特定的行为。然后让您的调度逻辑在适当的时间安排适当的线程。

否则,您有一个具有两个职责且需要了解调度的对象。

我个人也会从当前的getDelay()和一些复制调度管理器对象中获取调度逻辑,该对象也会保持状态(例如,最近执行的内容)。

最后,你可能想为你的日程安排人员使用图书馆的东西,我觉得你正在重新发明一些轮子。

答案 1 :(得分:3)

不要构建自己的调度程序,使用现有的调度程序。

如果要在Java中执行此操作,请使用quartz并为在不同计划上运行的增量备份和完全备份安排2个单独的任务。

但是在你的情况下,一个简单的cron脚本可能就好了。如果您在Windows上运行,请在Windows帮助文件中搜索Scheduled Tasks

修改
这是crontab,它可以避免同时运行full和incremental:

*/15 0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 * * * /path/to/run-incremental-backup.sh
15,30,45 1 * * * /path/to/run-incremental-backup.sh
0 1 * * * /path/to/run-full-backup.sh

在shell脚本中设置java环境并运行负责任务的java程序。

Quartz调度可以非常精细调整,其中一个标准调度程序完全模仿crontab。我将此作为练习留给读者。

顺便说一句,我已安排您的完整备份在凌晨1点运行,请参阅下面原因。

关于夏令时的说明
我不知道你在世界的哪个地方,如果你是少数幸运儿之一,你没有夏令时,否则请咨询当地时区当局。在北美,标准到日光在凌晨2点发生,白天到标准在凌晨3点,所以如果您的完整备份安排在凌晨2点,那么一年一天(S到D)您的完整备份将没有跑,另一天(D到S)会跑两次。