Java 将FutureTask用于异步进程时出现问题

Java 将FutureTask用于异步进程时出现问题,java,asynchronous,futuretask,Java,Asynchronous,Futuretask,在我的Java web应用程序中,我有一个方法,可以发送大约200封电子邮件。由于电子邮件服务器延迟,整个过程大约需要7分钟。此批量电子邮件发送必须作为用户操作的结果进行。当然,我不希望用户在转发到下一个线程之前等待那么久,更不用说Apache超时了,因此我尝试实现FutureTask,以使进程在单独的线程中运行,同时继续执行下面的代码: Some code; Runnable r = (Runnable)new sendEmails(ids); FutureTask task = new F

在我的Java web应用程序中,我有一个方法,可以发送大约200封电子邮件。由于电子邮件服务器延迟,整个过程大约需要7分钟。此批量电子邮件发送必须作为用户操作的结果进行。当然,我不希望用户在转发到下一个线程之前等待那么久,更不用说Apache超时了,因此我尝试实现FutureTask,以使进程在单独的线程中运行,同时继续执行下面的代码:

Some code;

Runnable r = (Runnable)new sendEmails(ids);
FutureTask task = new FutureTask(r, null);
Thread t = new Thread(task);
t.start();

Some more code;

但是,该应用程序仍在等待FutureTask完成后再继续。我愿意接受这样的想法,即这也不是在另一个线程中运行某些代码的最佳方式,同时继续脚本的其余部分。有没有更好的方法/如何使这一个工作?

看起来您在for循环中旋转了200多个线程。这将给机器带来很高的负担,并且由于分配给每个线程的每个堆栈的大小,在JVM耗尽内存之前不会占用太多线程,最初会导致大量GC和JVM锁定,然后可能在足够高的负载下崩溃

遗憾的是,这可能解释不了为什么您的代码等待将来的任务完成。它可能只是通过创建/调度这么多线程来等待适当的抖动;但话说回来,情况可能并非如此。很可能还有其他东西正在同步您的代码,这是从上面的代码片段中删掉的

您可以通过在运行代码时点击ctrl-break(假设您是从命令行运行的,intellij/eclipse都有一个方便的堆栈转储图标)来找到隐藏在某处的复杂同步。这将导致系统中每个线程出现堆栈转储。通过这样做,您将能够找到等待未来任务完成的用户线程,并且它将指出它正在等待哪个监视器。如果它没有等待,那么你就有另一个问题。例如,系统在短时间内反复创建大量线程,以至于它似乎在短时间内锁定了一些线程

但首先我要避免过多的线程创建部分,因为这可能会掩盖问题。我建议使用与以下类似的代码:

ExecutorService scheduler = Executors.newCachedThreadPool() 
scheduler.submit( task )

这不应该是阻塞,除非您在任务的
Some more code
块的某个地方调用
get
。是否要在线程完成其任务后执行某些操作?然而,你所说的
是什么意思?在继续之前,应用程序仍在等待未来任务完成?代码中没有阻塞调用。我没有调用get,也不需要返回。这意味着,当我调用此代码时,其他一些代码(这只是一个将用户转发到页面的调用)在Runnable完成之前不会执行。修复了它
private类sendLGORejectionEmails实现可运行的{private final String ids;private sendLGORejectionEmails(String param){ids=param;}public void run(){Send the emails;}}
Chris K的帮助。for循环不在上述代码之外,而是在sendmails函数内部。我之前尝试过一些执行器,但我会尝试你的安排,看看它是否有效。似乎它会在继续之前等待任务完成。但是,我收到此错误消息:java.lang.ClassCastException:my.application.CurrentClass$sendEmails无法转换为java.lang.RunnablesendEmail如下所示:“private class sendEmails”{private sendmails(String id){发送电子邮件的代码;}}'。当将implements Runnable添加到类Runnable时,我必须使用run(),我无法将ids变量传递到该类。