2013-03-01 29 views
0

在我的Java Web应用程序中,我有一个结束大约200封电子邮件的方法。由于电子邮件服务器延迟,整个过程大约需要7分钟。此批量电子邮件发送必须发生在用户操作的结果中。我当然不希望用户在转发到下一个版本之前必须等待很长时间,而不是说Apache无论如何都不会超时,所以我试图实现FutureTask来让进程在单独的线程中运行,同时继续其余代码如下:使用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完成,然后再继续。我接受这样的想法,即在继续执行脚本的其余部分的同时,这也不是在另一个线程中运行一些代码的最佳方式。有更好的方法/我如何使这个工作?

+0

这应该不会被阻止,除非您在'More some code'块中某个地方调用'get'任务。 – yakshaver 2013-03-01 18:14:11

+0

线程完成工作后,您是否想要执行一些操作? “你的意思是什么?”然而,应用程序仍然等待FutureTask在继续之前完成?您的代码中没有阻止呼叫。 – 2013-03-01 18:14:48

+0

我不打电话过去,我不需要退货。意思是说,当我调用这段代码时,“更多的代码”(只是将用户转到页面的调用)在Runnable完成之前不会执行。 – sgd 2013-03-01 18:49:00

回答

0

它看起来像你在for循环中旋转200多个线程。这会给机器带来很大的负担,并且由于每个线程分配的每个堆栈的大小,在JVM耗尽内存之前,它不会占用太多的线程,最初会导致大量的GC和JVM锁定,然后潜在地在足够高的负荷下,发生碰撞。

不幸的是,这可能或不可能解释为什么你的代码正在等待FutureTasks完成。它可能似乎只是通过创建/调度如此之多的线程来等待正常的抖动;但之后它可能不会。可能还有其他的东西正在同步你的代码,这些代码已经被删除掉了上面的代码片断。

找到隐藏在某处的技巧性同步的方法是在运行代码时按ctrl-break(假设您从命令行运行,intellij/eclipse都有一个堆栈转储图标,很方便)。这将导致出现系统中每个线程的堆栈转储。通过这样做,您将能够找到正在等待未来任务完成的用户线程,并且会说明它正在等待哪个监视器。如果它不在等待,那么你有一个不同的问题。例如,系统会在短时间内创建如此多的线程,以至于在短时间内出现锁定或某些情况。

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

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

for循环不在上面的代码之外,它在sendEmails函数中。我已经尝试过一些执行者,但我会尝试你的安排,看看它是否有效。 – sgd 2013-03-01 19:36:29

+0

似乎它在继续前等待任务完成。 – sgd 2013-03-01 19:48:44

+0

但是我收到了这个错误消息:java.lang.ClassCastException:my.application.CurrentClass $ sendEmails不能转换为java.lang.Runnable – sgd 2013-03-01 19:51:24

相关问题