我有一个非常复杂的系统(100多个线程)需要发送电子邮件而不会阻塞。我对这个问题的解决方案是实现一个名为EmailQueueSender
的类,它在执行开始时启动,并且有一个ScheduledExecutorService
,它每隔500毫秒查看一个内部队列,如果size()> 0则清空它
虽然正在进行,但有一个名为addEmailToQueue(String[])
的同步静态方法接受一个包含body,subject..etc作为数组的电子邮件。系统确实有效,我的其他线程可以继续将他们的电子邮件添加到队列中而不会阻塞,甚至担心电子邮件是否成功发送...它似乎有点乱......或者说是hackish ...每个程序员当他们知道自己做错了什么或者有更好的方法时,会在胃里感受到这种感觉。也就是说,有人可以拍我的手腕并提出一种更有效的方法来实现这一目标吗?
谢谢!
答案 0 :(得分:5)
http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html
这个课程本身可能会处理你需要的大部分内容。 只需将发送代码放在runnable中,然后使用execute方法添加它。 getQueue方法将允许您检索当前的等待项列表,以便您可以在重新启动发件人服务时保存它而不会丢失电子邮件
答案 1 :(得分:3)
如果您使用的是Java 6,那么您可以大量使用java.util.concurrent
包中的基元。
拥有一个处理实际发送的单独线程是完全正常的。我宁愿使用BlockingQueue
而不是轮询队列,因为您可以使用阻止take()
而不是忙碌等待。
如果您对电子邮件是否成功发送感兴趣,您的追加方法可能会返回Future
,以便您在发送邮件后可以传递返回值。
我建议创建一个(几乎无关紧要的)Java类来保存值,而不是使用字符串数组。如今,对象创建很便宜。
答案 2 :(得分:1)
我不确定这是否适用于您的应用程序,但听起来就是这样。 ThreadPoolExecutor
(ExecutorService
- 实现)可以将BlockingQueue
作为参数,您只需将新线程添加到队列中即可。完成后,您只需终止ThreadPoolExecutor
。
private BlockingQueue<Runnable> queue;
...
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, new Long(1000),
TimeUnit.MILLISECONDS, this.queue);
您可以保留添加到队列中的所有线程的计数。当你认为你已经完成时(队列是空的,或许?)只需将其与
进行比较 if (issuedThreads == pool.getCompletedTaskCount()) {
pool.shutdown();
}
如果两者匹配,你就完成了。终止池的另一种方法是在循环中等待一秒:
try {
while (!this.pool.awaitTermination(1000, TimeUnit.MILLISECONDS));
} catch (InterruptedException e) {//log exception...}
答案 3 :(得分:0)
可能已经有一个完整的邮件包,但我可能会从Spring对email和job scheduling的支持开始。为每个要发送的电子邮件发起新工作,并让执行者的时间发送作业,并担心需要完成多少工作。没有排队。
在框架下面,Spring使用Java Mail作为电子邮件部分,并允许您在ThreadPoolExecutor(由@Lorenzo提及)或Quartz之间进行选择。石英在我看来更好,因为你甚至可以设置它,以便它像cron作业一样在固定的时间点发射你的工作(例如在午夜)。使用Spring的优势在于它极大地简化了使用这些软件包的工作,因此您的工作更加轻松。
答案 4 :(得分:0)
有许多软件包和工具可以帮助解决这个问题,但是在计算机科学中广泛研究的类似案例的通用名称是producer-consumer problem。有各种众所周知的解决方案,可以被认为是“设计模式”。