【发布时间】:2016-11-30 15:28:10
【问题描述】:
我有一个 Java 应用程序(在 WAS 8.5 上运行),它充当客户端的一种服务器清单。该应用程序有一个 servlet,可触发长时间运行的进程。
流程:从第三方数据库获取数据,执行 Java 逻辑,将记录写回应用程序自己的数据库(这些数据库连接是池化的)。
servlet 不是在启动时加载的,并且每月仅由单个操作人员手动触发一次(在某个特定日期基于客户每月的选择)。 servlet 在历史上一直以这种方式使用 Timer 和 TimerTask:
public class SyncMissingServlet extends HttpServlet implements Servlet{
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
try{
SyncMissing.runSync();
}catch(Exception ex){
logger.error(new LogMessage("ERROR: "), ex);
this.sendReply(printWriter, "ERROR: " + ex.toString());
}
}
}
public class SyncMissing
{
public static void runSync() throws Exception
{
Timer t = new Timer(true);
SyncMissingTask task = new SyncMissingTask(); //SyncMissingTask is an instance of TimerTask
// Start the synchronization 5 secs from now, and run it every 30 days.
t.schedule(task, 5000, 2592000000l); //this 30 day timings never really worked out for the client,
//since the app server is restarted frequently for deployments.
}
}
当前代码中没有使用 Timer.close() 或 TimerTask.close()。 最近这个 Servlet 似乎已经自动触发了,在系统重新启动并重新启动系统上的 WAS 服务之后......这就是担心。
虽然我无法向我的客户解释自动触发器,但我提出了以下选项:
1. 放弃使用 Timer 和 TimerTask(长时间运行的进程然后在 servlet 的线程本身上运行)
2. 代替 TimerTask,将其设为常规 Runnable,并在 servlet 线程内的单独线程中运行。
3.利用Java的Executor Service
4. 迁移到 Servlet 3.0,将 servlet 变成 Async servlet。
5. 完全放弃 servlet,并用批处理作业替换它。
我知道选项 3 和 4 确实是推荐的选项(或者可能是选项 5)。但我有一种感觉,在我的业务场景中 - 选项 3 和 4 可能是矫枉过正。
如果确实需要每月只有一个用户手动调用 servlet,选项 1 和 2 有那么糟糕吗? (我的客户想要最快的解决方案,当然不会资助选项 5)
【问题讨论】:
-
“单数据库连接”是指单例吗?您是否仅限于 JVM 中的一个连接?如果是这样,这就产生了问题。编辑您的问题以澄清。
-
对不起。我现在已经更新了那部分。所有数据库连接都是池化的(包括连接到第三方数据库的连接)。此外,第三方数据库连接仅发生在整个应用程序中的这个 servlet...这个 servlet 有点独立,这个长时间运行的过程的结果不会从应用程序的任何其他模块引用。
-
您还没有真正说出问题的确切性质。您是否希望任务每个日历月运行一次,但即使服务器重新启动也严格只运行一次?如果是这样,您需要在某处记录执行该任务的上一年月。在执行任务之前检查存储的值。
-
@Basil Bourque:你是正确的。作为第二步,我已经计划好了(记录最后一次运行的时间戳,以确保它严格每月运行一次)。但是,我首先尝试了解在我的情况下是否存在任何性能问题 - 如果我在 servlet 线程本身(或其中的并行线程)中运行该进程。我的场景 - 每个月只有一个计划的对 servlet 的请求。
标签: java multithreading servlets