在Web应用程序中我有一个方法,如果客户数量小于10,则等待另一个线程生成报告,但如果大于10,我会启动我的线程但不应用join方法,当线程完成时我通过电子邮件通知。
我对有大量执行的孤立线程以及对服务器的影响有点害怕。
好的发射是一个重的"在后台进程(异步)而不使用join方法或有更好的方法来实现它?
try {
thread.start();
if(flagSendEmail > 10){
return "{\"message\":\"success\", \"text\":\"you will be notified by email\"}";
}else{
thread.join(); //the customer waits until finish
}
} catch (InterruptedException e) {
LogError.saveErrorApp(e.getMessage(), e);
return "{\"message\":\"danger\", \"text\":\"can't generate the reports\"}";
}
答案 0 :(得分:2)
Orphan线程不是问题,只需确保run()
方法有一个发送电子邮件的finally块。
问题是你无法控制线程数,这与调用join()
无关。 (除非你总是等待调用者中的每一个线程,否则一开始就没有必要启动后台线程。)
解决方案是使用ExecutorService
,它为您提供线程池,从而精确控制一次运行这些后台线程的数量。如果您提交的任务数超过执行程序在给定时间可以处理的任务数,则其余任务将排队等待运行。这样您就可以控制服务器上的负载。
额外的好处是,因为执行程序服务通常会回收相同的工作线程,所以提交新任务的开销较小,这意味着您无需担心自己是否拥有超过10个项目或不,一切都可以以同样的方式运行。
在您的情况下,您甚至可以考虑使用两个单独的执行程序:一个用于运行报告生成,另一个用于发送电子邮件。这样做的原因是您可能希望限制在繁忙时段发送的电子邮件数量,但不会减慢报告生成速度。
答案 1 :(得分:2)
如果您接下来做的事情是join()
,那么启动一个主题是没有意义的。
我不确定我理解你要做什么,但是如果你的例子是在正确的道路上,那么这将更好,因为它避免了在{{中创建和销毁新线程(昂贵) 1}}案例:
flagSendEmail <= 10
但是很有可能,你根本不应该明确地创建新的线程。每当程序不断地创建并销毁线程时,这就表明它应该使用线程池。 (参见Runnable r = ...;
if (flagSendEmail > 10) {
Thread thread = new Thread(r);
thread.start();
return "...";
} else {
r.run();
return ???
}
)的javadoc
顺便说一句:java.util.concurrent.ThreadPoolExecutor
对线程t.join()
没有任何作用。除了等待线程t
已经死亡之外,它根本不做任何事情。
答案 2 :(得分:0)
是的,它是安全的,我不记得看到任何Thread#join()
实际调用。
但这取决于你想做什么。我不知道您是否要使用生成报告或分配了一些资源的池或线程。在任何情况下,您都应该将自己限制为报告的最大线程数。如果它们被阻塞或循环(对于某些错误或差的同步),允许越来越多的线程将完全阻塞您的应用程序。
Thread#join
等待引用的线程死亡。那些线程真的结束了吗?你是否在等待一个线程只是为了启动另一个线程?通常在同步对象上使用wait()
和notify()
进行同步。
启动一个进程(Runtime#exec()
)可能会让事情变得更糟,除非它有助于解决一些奇怪的限制。
有一些像JConsole这样的工具可以让你对线程被锁定和其他问题有所了解。