3

我正在编写一个消息处理应用程序(电子邮件),我想要一个传出队列。我设计这个的方式是有一个单例队列类,ThreadedQueueSender,由一个 Executor Service 和一个 BlockingQueue 支持。此外,javax.mail.Transport 对象的线程池用于获取和释放与传出 SMTP 服务器的连接。

此类公开了一个方法,add(MimeMessage)该方法将消息添加到工作队列 ( BlockingQueue)。

在类的实例化时,它ExecutorService被初始化为ThreadPoolExecutor具有固定数量的线程,比如说 5。每个线程的run()方法都处于无限循环中,只有在检测到中断时(ExecutorService.shutdownNow()被调用时)才退出。

此运行方法用于BlockingQueue.poll()从工作队列中获取消息,直到没有更多可用而不阻塞,然后Transport从连接池请求一个对象,打开连接,发送它检索到的所有消息,关闭连接并返回Transport对象。

这行得通,但我觉得我没有通过在应用程序的生命周期内运行固定数量的线程来充分利用 ExecutorService。此外,我自己管理工作队列,而不是让并发框架处理它。其他人将如何实现此功能?将每个传入消息包装在 Runnable 中,然后执行发送逻辑是否更好?

谢谢,任何意见表示赞赏。

瑞安

4

2 回答 2

1

您应该为执行程序服务应该完成的每一项工作创建任务。

例如,您可以创建一个可调用的“MailSendingTask”,它保存 MimeMessage 并包装邮件发送。通过将这些 MailSendingTasks 提交给您的 executor 来对它们进行排队。现在您的 Executor 决定将创建多少个线程(通过设置上下线程池边界来配置它)

您只需要创建 2 或 3 个类/接口

  • 一个提供简单 send(MimeMessage msg) 方法的 MailService 接口
  • 一个 MailServiceImplementation 类,它实现 MailService 并持有对已配置执行程序的引用
  • 一类 MailSenderTask 实现可调用接口,该接口包含对 MimeMessage 对象的引用并进行邮件发送。

您甚至可以通过创建一个额外的服务来管理 MailSenderTask 可以使用的邮件套接字连接,从而更进一步。

如果您想添加“取消”,您应该查看 Future 和 FutureTask 类

于 2009-09-28T18:35:34.333 回答
0

将消息包装在 aRunnable中将迫使您要么使工作队列无界,要么处理队列已满时发生的情况。 ThreadPoolExecutor为您提供了一些处理这种情况的策略 - 有关详细信息,请参阅ThreadPoolExecutor javadoc。- 放弃,自己经营/丢弃一些东西

您可以做的另一件事是允许线程池创建超出其核心大小的线程,线程如何产生以及何时获得它们由ThreadPoolExecutor构造函数的前 4 个参数描述。这在现实中的效果将取决于资源瓶颈。

另外,BlockingQueue.poll在您的情况下有什么优势,而不是BlockingQueue.take?两者都是可中断的,你的线程只有一个任务,所以阻塞是不可取的。

于 2009-09-28T18:34:53.237 回答