我有一种方法可用于发送电子邮件。我想锁定这个方法,所以每次只有一个线程可以接受它,并且其余的池同时存在。我应该同步方法还是使用spring @transactional PROPAGATION_REQUIRED?
//each time use new thread to send out email
public void sendThroughSMTP(List<String> emails,String subject,String content){
//each time will open and sent through port 25. dont u think this will caused too many threads spawned?
BlastEmailThread blastEmailThread = new BlastEmailThread(emails,subject,content);
blastEmailThread.start();
}
答案 0 :(得分:7)
为什么不通过不使用任何实例级别的东西使方法线程安全?
但是,我没有看到Spring的交易管理如何适合这里。我的意思是Spring提供了很少的事务管理器,即DataSourceTransactionManager
,JtaTransactionManager
,HibernateTransactionManager
所有这些都与数据库持久性有关。您将为此电子邮件发送什么配置?
我相信,首先你要告诉我们为什么你首先担心线程安全。很可能您想向我们展示一些相关的代码片段或其他内容。然后我们可能会建议你。
<强> [附录] 强>
当您为该方法的每次调用生成一个线程而不使用该状态中的任何内容时,那么为什么要创建方法synchronized
。使方法同步不会以任何方式限制线程数。在启动新线程之前,由于同步,前一个线程可能已经完成了工作。产生线程的过程可能会变慢。
但是,你应该继续使用它,直到你发现有很多线程正在运行并且你的内存不足。如果你真的想在时间之前解决这个问题,那么你应该选择一些阻塞机制,比如Semaphore。
答案 1 :(得分:3)
在Sping 3.0中,您可以使用@Async批注来执行任务,因此您的方法将在稍后执行,并且方法将直接返回,而无需等待发送电子邮件。
@Async
public void sendThroughSMTP(List<String> emails,String subject,String content){
//Send emails here, you can directly send lots of email
}
然后在应用程序上下文中指定并且不要忘记为任务模式添加xmlns。
如果要延迟执行一段时间,可以在方法中使用@Scheduled注释。
有关@Async和@Scheduled的进一步教程可以在这里找到:
http://blog.springsource.com/2010/01/05/task-scheduling-simplifications-in-spring-3-0/
答案 2 :(得分:2)
另一种可能性是使用JMS队列并将电子邮件发送代码放在消息驱动Bean(或通过Spring JMS)中。然后,您可以使用您的应用服务器来控制将使用多少MDB并发实例,并以此方式限制外发电子邮件。
答案 3 :(得分:1)
我不确定它是否回答了您的问题,但是不是为每封邮件创建一个新主题,而是在其上调用start,您可以拥有Executor或ExecutorService作为您班级的成员,作为一种实现,您可以使用池大小为1的ThreadPoolExecutor。然后,您的sendMail方法会将Runnables提交给执行者。
答案 4 :(得分:1)
Spring @Transactional在您的情况下使用不太正确。最好的办法是使用同步方法并添加一些线程池,如果您的方法调用数百次。但我猜你不需要线程池。
如果您使用线程发送爆炸电子邮件,那么同步该方法的重点是什么?如果一个进程调用您的方法并发送电子邮件,其他进程将调用您方法,即使第一个发送电子邮件进程尚未完成。
如果您打算限制电子邮件发送过程,则需要调整队列(集合)并使用synchronize块保护集合。创建另一个进程来监视该队列,如果队列中有一个项目,弹出它并发送爆炸电子邮件,然后等待发送电子邮件进程完成并再次检查队列,如果有任何项目,继续发送电子邮件进程。如果队列中没有项目,则使监视器线程休眠一段时间,如果休眠时间结束,则再次检查队列。
答案 5 :(得分:0)
将您的服务设为singleton
并将synchronized
添加到您的方法中。