繁体   English   中英

用于线程队列的设计模式

[英]What design pattern to use for a threaded queue

我有一个非常复杂的系统(100多个线程)需要发送电子邮件而不会阻塞。 我解决这个问题的方法是实现一个名为EmailQueueSender的类,该类在执行开始时启动,并有一个ScheduledExecutorService ,它每隔500ms查看一个内部队列,如果size()> 0则清空它。

虽然这是一个名为addEmailToQueue(String[])的同步静态方法,它接受一个包含body,subject..etc作为数组的电子邮件。 系统确实有效,我的其他线程可以继续将他们的电子邮件添加到队列中而不会阻塞,甚至担心电子邮件是否成功发送...它似乎有点乱......或者说是hackish ...每个程序员当他们知道自己做错了什么或者有更好的方法时,会在胃里感受到这种感觉。 也就是说,有人可以打我的手腕,并提出一个更有效的方法来实现这一目标吗?

谢谢!

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html

仅此课程可能会处理您需要的大部分内容。 只需将发送代码放在runnable中,然后使用execute方法添加它。 getQueue方法将允许您检索当前的等待项列表,以便您可以在重新启动发送方服务时保存它而不会丢失电子邮件

如果您使用的是Java 6,则可以大量使用java.util.concurrent包中的原语。

拥有一个处理实际发送的单独线程是完全正常的。 我宁愿使用BlockingQueue而不是轮询队列,因为你可以使用阻塞take()而不是busy-waiting。

如果您对电子邮件是否成功发送感兴趣,您的append方法可以返回Future以便您可以在发送邮件后传递返回值。

我建议创建一个(几乎无关紧要的)Java类来保存值,而不是使用字符串数组。 如今,对象创建很便宜。

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

可能已经有一个完整的邮件包,但我可能会从Spring的电子邮件作业调度支持开始。 为每个要发送的电子邮件发起新工作,并让执行者的时间发送作业,并担心需要完成多少工作。 没有排队。

在框架下面,Spring使用Java Mail作为电子邮件部分,并允许您在ThreadPoolExecutor(由@Lorenzo提及)或Quartz之间进行选择。 石英在我看来更好,因为你甚至可以设置它,以便它像cron作业一样在固定的时间点发射你的工作(例如在午夜)。 使用Spring的优势在于它大大简化了使用这些软件包的工作,因此您的工作更加轻松。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM