如何创建一个执行TimerTasks的守护进程?

huangapple go评论72阅读模式
英文:

How do I create a daemon which executes TimerTasks?

问题

我需要在Java中创建一个守护进程,定期通过HTTP检索数据并将其存储在数据库中。

当主线程启动时,它从配置文件中读取数据源和轮询间隔,并为每个数据源创建一个具有适当间隔的TimerTask。此外,它调用Runtime.getRuntime().addShutdownHook()来添加一个在关闭之前执行任何所需清理的关闭钩子。在此之后,主线程没有其他事情要做。

该守护进程旨在在经典的Unix环境中使用,即通过启动/停止脚本进行控制,尽管它应该可以在其他操作系统中移植(比如,使用SrvAny的Windows)。

我应该如何处理这个问题?如果我只允许主线程退出,TimerTask实例会保持VM运行直到所有这些实例都被取消吗?如果不能,我应该如何实现这一点?

英文:

I need to create a daemon in Java which periodically retrieves data via HTTP and stores that in a database.

When the main thread starts up, it reads the data sources and poll intervals from a configuration file and creates a TimerTask with the appropriate interval for each data source. In addition, it calls Runtime.getRuntime().addShutdownHook() to add a shutdown hook which performs any cleanup needed before shutdown. After that, the main thread has nothing else to do.

The daemon is intended for use in a classic Unix environment, i.e. controlled with a start/stop script, though it should be portable to other OSes (say, Windows with SrvAny).

How would I go about this? If I just let the main thread exit, will the TimerTask instances keep the VM running until all of them have been cancelled? If not, how would I accomplish this?

答案1

得分: 1

依赖于安排了 TimerTaskTimer:如果该 Timer 被创建为非守护进程运行其任务,即使主线程完成工作后,挂起的 TimerTask 也将保持虚拟机的活动状态。对于所有不带有 boolean 参数的 Timer 构造函数,或者 boolean 参数为 false 的情况,都适用这种情况。

以下代码似乎按预期工作:

package com.example.daemon;

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

public class SampleDaemon {
    private static Timer testTimer = new Timer(false);

    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("Received shutdown request!");
                if (testTimer != null)
                    testTimer.cancel();
                testTimer = null;
            }
        });
        testTimer.schedule(new TestTimerTask(), new Date(), 2000);
    }

    private static class TestTimerTask extends TimerTask {
        @Override
        public void run() {
            System.out.println("Still running…");
        }
    }
}

它每隔 2 秒打印一次 Still running…。当 JVM 收到 SIGTERM 信号时,程序会打印出 Received shutdown request! 并退出。这也可以通过从控制台发送 Ctrl+C 来实现。SIGHUPSIGTERM 作用相同。

SIGCONT 没有影响;SIGUSR1 导致强制退出(可能与 SIGKILL 相同),即在不执行关闭钩子的情况下退出。

英文:

It depends on the Timer on which the TimerTask was scheduled: if that Timer was created not to run its tasks as daemons, a pending TimerTask will keep the VM alive even after the main thread has finished its work. This is the case for all Timer constructors which do not take a boolean argument, or where the boolean argument is false.

The following seems to work as intended:

package com.example.daemon;

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

public class SampleDaemon {
	private static Timer testTimer = new Timer(false);

	public static void main(String[] args) {
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				System.out.println("Received shutdown request!");
				if (testTimer != null)
					testTimer.cancel();
				testTimer = null;
			}
		});
		testTimer.schedule(new TestTimerTask(), new Date(), 2000);
	}

	private static class TestTimerTask extends TimerTask {
		@Override
		public void run() {
			System.out.println("Still running…");
		}
	}
}

It prints Still running… every 2 seconds. When the JVM receives a SIGTERM, the program prints Received shutdown request! and exits. This can also be accomplished by sending Ctrl+C from the console. SIGHUP does the same as SIGTERM.

SIGCONT has no effect; SIGUSR1 results in a hard exit (presumably the same as SIGKILL), i.e. without executing the shutdown hook.

答案2

得分: 1

在Java中,线程具有一个标志,用于指示它们是否应该保持JVM保持活动状态。这个标志被称为“daemon”:当只有守护线程在运行时,JVM将退出。

由Timer启动的线程默认上不是守护线程,因此它会保持JVM保持活动状态,这正是您想要的。如果您希望JVM退出,您可以使用new Timer(true)创建计时器 - 这将设置守护线程标志。https://docs.oracle.com/javase/10/docs/api/java/util/Timer.html#%3Cinit%3E(boolean)

英文:

Threads in Java have a flag to indicate if they should keep the jvm alive or not. This flag is called "daemon": the jvm will exit when only daemon threads are running.

The thread started by Timer is not a daemon thread by default, so it will keep the jvm alive, which is what you want. If you wanted the jvm to exit, you could create the timer with new Timer(true) - this would set the daemon flag. https://docs.oracle.com/javase/10/docs/api/java/util/Timer.html#%3Cinit%3E(boolean)

huangapple
  • 本文由 发表于 2020年4月6日 00:33:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/61045837.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定