如何处理doGet或doPost中可能长时间的操作?

在HTTP POST(由应用程序生成,而不是由用户生成)之后,我想发送电子邮件。我得到了正确的电子邮件发送程序,但我不确定Java webapp服务器是如何工作的。 我特别关注超时,我想知道我是否以某种方式阻止了一个重要的线程。 如果我执行以下操作:
    @Override
    public void doPost(
            final HttpServletRequest req,
            final HttpServletResponse resp
    ) throws IOException, ServletException {
        final PrintWriter pw = resp.getWriter();
        pw.write( ... );
        pw.flush();
        pw.close();
        // Here I'm sending an email, this can potentially
        // block until the email send procedure times out
        // (the timeout is set to 5 seconds)
        sendEmail(...);
    }
如果电子邮件服务器关闭,线程将阻塞,直到我的sendEmail超时(超时,我设置为几秒)。 我阻止哪个线程?我的意思是,显然我意识到我正在阻止正在处理此POST的线程,但这是一个问题吗?这个帖子下一步应该做什么? 我读到我不应该从Java webapp服务器创建新线程,所以我认为我不应该做以下事情吗?
    Thread t = new Thread( new Runnable() {
        public void run() {
            sendEmail();
        }
    });
    t.start();
请注意,我的问题不是特定于电子邮件发送:我想了解每次计划在GET或POST后执行可能阻塞/长时间操作时在Java Web应用程序中需要注意的事项。     
已邀请:
可以在servlet中启动一个线程,只需要非常小心,确保在取消部署servlet时它会死掉。 最简单的方法是在servlet启动时创建一个
java.util.concurrent.ExecutorService
,在servlet被销毁时关闭它。然后,您可以将您的电子邮件作业提交给执行者服务,并从
doPost
返回。请注意,如果在作业排队后销毁servlet,则可能无法发送某些电子邮件。 在代码中:
class EmailServlet extends HttpServlet {
    private ExecutorService emailSender;

    public void init() {
        emailSender = Executors.newFixedThreadPool(1);
    }

    public void destroy() {
        emailSender.shutdownNow();
    }

    public void doPost(...) {
        ...
        emailSender.execute(new Runnable() {public void run() {sendEmail();}});
    }
}
    
我的建议:存储你需要做的任务(即在数据库或队列中),通过第二个过程在后台处理它们,并尽快让你的
doPost
/
doGet
返回。用户不想等待。 例如,您可以接收外部应用程序请求,存储您需要在数据库中发送的电子邮件或将其放入JMS队列(许多应用程序服务器附带JMS功能但我从未使用它们),并返回。其他进程可能是读取该数据库/队列并发送电子邮件而不阻止HTTP响应。 关于在webapp中使用Threads,它可以工作,它可能是最简单的解决方案,但它也可能存在可伸缩性问题。如果你这样做,请确保使用某种线程池(
ExecutorService
...),因为Web服务器/操作系统通常对线程数有限制。     

要回复问题请先登录注册