每3分钟运行一次java类

时间:2016-04-13 18:17:51

标签: process scheduled-tasks java-service-wrapper

我尝试编写一个每3分钟运行一次的简单Java程序。 我正在使用Timer和TimerTask来调用这些类。

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class Receiver
{
    public static void main(String[] args)
    {
        System.out.println("Time now is -> " + new Date());

        Timer timer = new Timer();
        TimerTask task = new ReceiverTask();
        timer.scheduleAtFixedRate(task, 0, 180000);
    }
}

class DPGReceiverTask extends TimerTask
{
    private ArrayList<TaskArgs> m_tasks = new ArrayList<TaskArgs>();

    public ReceiverTask()
    {
        m_tasks.add(new TaskArgs("com.comp.Receiver", new String[] { "ARG1", "ARG2"}));
    }

    public void run()
    {
        System.out.println("Receiver Started!");

        String classpath = "D:/Receiver;D:/Receiver/lib/*";
        int i = 0;

        ArrayList<Process> processes = new ArrayList<Process>();
        for (TaskArgs task: m_tasks)
        {
            try
            {
                List<String> command = new ArrayList<String>();
                command.add(System.getProperty("java.home") + "/bin/java");
                command.add("-classpath");
                command.add(classpath);
                command.add(task.Name);

                String[] args = task.Args;
                for (String arg : args)
                {
                    command.add(arg);
                }

                Process process = new ProcessBuilder(command).start();
                processes.add(process);

            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        try
        {
            for (Process process : processes)
            {
                int exitCode = process.waitFor();
            }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}
public class TaskArgs
{
    public TaskArgs(String name, String[] args)
    {
        Name = name;
        Args = args;
    }

    public String Name;
    public String[] Args;
}

我实现了winsw并创建了运行bat文件的服务,而bat文件又运行java:

receiverTask.bat

java -classpath ReceiverService.jar Receiver

receiverTask.xml

<service>
  <id>receiverTask</id>
  <name>receiverTask</name>
  <description>receiver Service</description>
  <executable>receiverTask.bat</executable>
  <logpath>D:\winsw\logs\Service</logpath>
 <log mode="roll-by-time">
  <pattern>yyyyMMdd</pattern>
    </log>
  <depend>Spooler</depend>
  <startargument>run</startargument>
  <stopargument>stop</stopargument>
</service>

我对当前的实现有两个问题:

  1. 无论当前的java完成与否,Timer都将在3分钟内启动另一个进程。
  2. 停止服务(winsw-java服务包装器)不会停止运行java.exe或cmd.exe的进程
  3. 我尝试添加destroy方法来杀死进程,但这真的是要走的路吗?

            ...    
            try
            {
                for (Process process : processes)
                {
                    Timer t = new Timer();
                    TimerTask killer = new TimeoutProcessKiller(process);
                    t.schedule(killer, 178000);
                    int exitCode = process.waitFor();
                    killer.cancel();
                }
            }
    
    public class TimeoutProcessKiller extends TimerTask
    {
        private Process p;
        public TimeoutProcessKiller(Process p)
        {
            this.p = p;
        }
    
        public void run()
        {
            p.destroy();
        }
    }
    

    有人有任何建议吗?

2 个答案:

答案 0 :(得分:1)

如果通过调用ProcessBuilder.start()从Java应用程序中启动进程,则可以使用有效的Process引用,并且可以调用Process类中的destroy()方法来终止该特定进程。因此,您应该在创建新流程之前遍历您的列表,并在存在某些流程时将其销毁。

class DPGReceiverTask extends TimerTask {
    private ArrayList<TaskArgs> m_tasks = new ArrayList<TaskArgs>();
    private LinkedList<Process> processes = new LinkedList<Process>();

    public ReceiverTask() {
        m_tasks.add(new TaskArgs("com.comp.Receiver", new String[] { "ARG1", "ARG2"}));
    }

    public void run() {
        // shutdown prev. created processes
        for (Process process: processes) {
            process.destroy();
        }
        processes.clear();

        System.out.println("Receiver Started!");

        String classpath = "D:/Receiver;D:/Receiver/lib/*";
        int i = 0;

        for (TaskArgs task: m_tasks) {
            try {
                List<String> command = new ArrayList<String>();
                command.add(System.getProperty("java.home") + "/bin/java");
                command.add("-classpath");
                command.add(classpath);
                command.add(task.Name);

                String[] args = task.Args;
                for (String arg : args)
                {
                    command.add(arg);
                }

                Process process = new ProcessBuilder(command).start();
                processes.add(process);

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

答案 1 :(得分:1)

使用Timer是进行此类调度的比较粗略的方法。

该类文件的第七段甚至建议使用下面描述的替代方案。

  

Java 5.0引入了java.util.concurrent包...用于以给定的速率或延迟重复执行任务...更多用户代替Timer / TimerTask ......

执行人

Java 5及更高版本提供Executor framework来处理此类任务。

具体来说,您需要ScheduledExecutorService。这解决了你的问题。

  • 服务在执行下一个作业之前等待待处理作业完成。
  • 该服务为您提供ScheduledFuture对象,通过该对象可以检查其状态并停止进一步的工作。 cancel方法允许您指定是否要等到当前作业完成,或者尝试中断当前作业。

学习

搜索Stack Overflow以获取使用ScheduledExecutorService的许多示例。

您需要花一点时间和精力将头部缠绕在活动部件上。但是,在应用程序中生成的代码花费的时间是处理线程后台作业的挑战的一种非常简单和优雅的方式。

我不会在这里开始阅读,但稍后您可能会发现this answer of mineScheduledExecutorService驱动的完整工作示例Vaadin应用有帮助。

买者

谨防一个关键技巧:使用Callable <围绕Runnable / call对象的run / try-catch方法的外部/ strong>因为任何未捕获的异常到达服务会导致服务停止调度其他作业。这种停止工作的特征是默默地发生的。此行为是一个功能,而不是错误。

解决方法很容易捕获Callable / Runnable对象中的任何Exception(可能还有任何Throwable) - 无论如何都是有道理的,因为任何未捕获的异常达到该级别意味着出现了问题您希望了解并编辑代码,以便在实施中进一步处理。

有关详细信息,请参阅此问题:ScheduledExecutorService Exception handling