我正在编写一个消息处理应用程序(电子邮件),我想要一个传出队列。我设计的方式是拥有一个单例队列类ThreadedQueueSender,由Executor Service和BlockingQueue支持。此外,javax.mail.Transport对象的线程池用于获取和释放与传出SMTP服务器的连接。
此类公开了一个方法add(MimeMessage)
,该方法将消息添加到工作队列(BlockingQueue
)。
在实例化类时,ExecutorService
被初始化为具有固定线程数的ThreadPoolExecutor
,让我们说5.每个线程的run()
方法都处于无限循环中,只退出当它检测到中断时(调用ExecutorService.shutdownNow()
时)。
此run方法使用BlockingQueue.poll()
从工作队列中获取消息,直到没有阻塞不再可用,然后从连接池请求Transport
对象,打开连接,发送所有消息检索,关闭连接并返回Transport
对象。
这样可行,但我觉得我没有充分利用ExecutorService,因为它有一定数量的线程在应用程序的生命周期内运行。此外,我自己管理工作队列,而不是让并发框架处理它。其他人如何实现此功能?将每个传入消息包装在Runnable中更好,然后执行发送逻辑吗?
谢谢,任何评论都表示赞赏。
赖安
答案 0 :(得分:1)
您应该为执行者服务应该完成的每项工作创建任务。
例如,您可以创建一个可调用的“MailSendingTask”来保存MimeMessage并包装邮件发送。通过将这些MailSendingTasks提交给您的遗嘱执行人来排队。现在您的执行程序决定将创建多少个线程(通过设置较低和较高的线程池边界来配置它)
您只需创建2个或3个类/接口
您甚至可以通过创建管理MailSenderTask可以使用的邮件套接字连接的额外服务来进一步发展。
如果你想添加“取消”,你应该看看Future和FutureTask类
答案 1 :(得分:0)
在Runnable
中包装消息会强制您使工作队列无限制或处理队列已满时发生的事情。 ThreadPoolExecutor
为您提供了一些处理此情况的政策 - 有关详细信息,请参阅ThreadPoolExecutor javadoc。 - 放弃,自己运行/丢弃某些东西
您可以做的另一件事是允许线程池创建超出其核心大小的线程,如何生成线程以及何时获取线程由ThreadPoolExecutor
构造函数的前4个参数描述。这在现实中如何运作将取决于资源瓶颈。
另外,BlockingQueue.poll
在你的情况下有什么优势,而不是BlockingQueue.take
?两者都是可中断的,并且你的线程只有一个任务,所以阻塞是不可取的。