用什么设计模式来实现一个线程队列?

3
我有一个非常复杂的系统(100+线程),需要发送电子邮件而不会阻塞。我的解决方法是实现一个名为EmailQueueSender的类,在执行开始时启动它,并拥有一个ScheduledExecutorService,每500毫秒查看内部队列,如果size()> 0,则清空队列。
同时进行的是一个同步的静态方法addEmailToQueue(String[]),它接受一个包含正文、主题等电子邮件内容的数组。系统可以正常工作,我的其他线程可以在将其电子邮件添加到队列后继续移动,而无需阻塞或甚至担心电子邮件是否成功发送...但它似乎有点凌乱...或者说是hackish...每个程序员都会有这种感觉,当他们知道自己在做错事情或者有更好的方法时。
因此,请问是否有更有效的方法来完成这项任务?谢谢!
5个回答

5

3
如果您使用的是Java 6,则可以大量使用java.util.concurrent包中的原语。
拥有一个单独的线程来处理实际发送是完全正常的。我不想使用轮询队列,而是更愿意使用BlockingQueue,因为您可以使用阻塞的take()而不是忙等待。
如果您对电子邮件是否成功发送感兴趣,您的附加方法可以返回一个Future,以便您在发送消息后传递返回值。
我建议创建一个(几乎微不足道的)Java类来保存值,而不是拥有一个字符串数组。对象创建现在很便宜。

正是我所需要的!已经实现并完美运行。我还将电子邮件更改为内部类,而不是数组...非常感谢 :) - Submerged

1

我不确定这是否适用于您的应用程序,但听起来似乎是可以的。 ThreadPoolExecutorExecutorService实现)可以将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...} 

0

可能已经有一个完整的邮件包存在,但我可能会从Spring的对电子邮件作业调度的支持开始。为每封要发送的电子邮件触发一个新任务,让执行器的定时发送任务并考虑需要完成多少任务。不涉及排队。

在框架下,Spring使用Java Mail进行电子邮件部分,并让您在ThreadPoolExecutor(由@Lorenzo提到)或Quartz之间选择。我认为Quartz更好,因为您甚至可以设置它,使其在固定时间点像cron作业(例如,在午夜时)触发作业。使用Spring的优点是它大大简化了与这些包一起工作的过程,因此您的工作更加轻松。


0

有许多软件包和工具可帮助解决这个问题,但是在计算机科学中广泛研究的此类情况的通用名称为生产者-消费者问题。 有各种各样的众所周知的解决方案,可以被视为“设计模式”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接