在 Tomcat 中运行后台 Java 程序

2022-09-01 01:32:54

任何人都可以在这里提供建议吗?我有一种情况,用户将通过Java JSP和servlet以交互方式将数据挖掘请求提交给我的应用程序,该应用程序将动态地制定数据等的关联规则。

由于这样的工作可能需要一段时间,我正在考虑在服务器上进行某种过程以在后台运行此类请求,因此它不会“锁定”会话,并且可能使用大量服务器内存来损害系统。

由于该系统由一系列Java JSP和servlet组成,这些Java JSP和servlet在MySQL数据库的Tomcat容器中运行,任何人都可以建议前进的道路吗?

谢谢

摩根先生


答案 1

使用执行器服务

但是,您应该做一些事情,将线程标记为守护进程线程,以便它至少在错误情况下不会占用tomcat,并且您应该在servlet上下文被破坏时停止执行器(例如,当您重新部署或停止应用程序时)。为此,请使用 ServletContextListener:

public class ExecutorContextListener implements ServletContextListener {
    private  ExecutorService executor;

    public void contextInitialized(ServletContextEvent arg0) {
        ServletContext context = arg0.getServletContext();
        int nr_executors = 1;
        ThreadFactory daemonFactory = new DaemonThreadFactory();
        try {
            nr_executors = Integer.parseInt(context.getInitParameter("nr-executors"));
        } catch (NumberFormatException ignore ) {}

        if(nr_executors <= 1) {
        executor = Executors.newSingleThreadExecutor(daemonFactory);
        } else {
        executor = Executors.newFixedThreadPool(nr_executors,daemonFactory);
       }
          context.setAttribute("MY_EXECUTOR", executor);
      }

    public void contextDestroyed(ServletContextEvent arg0) {
        ServletContext context = arg0.getServletContext();
        executor.shutdownNow(); // or process/wait until all pending jobs are done
    }

}
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

/**
 * Hands out threads from the wrapped threadfactory with setDeamon(true), so the
 * threads won't keep the JVM alive when it should otherwise exit.
 */
public class DaemonThreadFactory implements ThreadFactory {

    private final ThreadFactory factory;

    /**
     * Construct a ThreadFactory with setDeamon(true) using
     * Executors.defaultThreadFactory()
     */
    public DaemonThreadFactory() {
        this(Executors.defaultThreadFactory());
    }

    /**
     * Construct a ThreadFactory with setDeamon(true) wrapping the given factory
     * 
     * @param thread
     *            factory to wrap
     */
    public DaemonThreadFactory(ThreadFactory factory) {
        if (factory == null)
            throw new NullPointerException("factory cannot be null");
        this.factory = factory;
    }

    public Thread newThread(Runnable r) {
        final Thread t = factory.newThread(r);
        t.setDaemon(true);
        return t;
    }
}

您必须将上下文侦听器添加到 Web.xml,还可以在其中指定要运行后台作业的线程数:

  <listener>
    <listener-class>com.example.ExecutorContextListener</listener-class>
  </listener>

您可以从 servlet 访问执行器并向其提交作业:

ExecutorService executor = (ExecutorService )getServletContext().getAttribute("MY_EXECUTOR");
...
executor.submit(myJob);

如果你正在使用Spring,所有这些都可以变得更加简单。


答案 2

我认为Quartz调度程序应该能够完成您想在这里做的事情。以下是Quartz的一些例子。使用此功能,您可以启动一个快速轮询以处理传入请求的 cron。我实际上为我的一个项目做了这件事。


推荐