同步方法还是使用Spring的@Transactional?

4

我有一个用于发送电子邮件的方法。我希望锁定此方法,以便每次只能有一个线程访问它,而其余线程则可以同时排队。我应该使用synchronized关键字来同步该方法,还是使用Spring的@Transactional(propagation=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();


}
6个回答

7
为什么不使用任何实例级别的东西来使方法线程安全?
然而,我不知道Spring的事务管理如何适用于这里。我的意思是,Spring提供了一些事务管理器,即DataSourceTransactionManagerJtaTransactionManagerHibernateTransactionManager,都与数据库持久化有关。那么你会为这个邮件发送配置什么呢?
我认为,首先你应该向我们展示为什么你首先担心线程安全。很可能你想向我们展示一些相关的代码片段或其他东西。然后我们可能能够为你提出建议。
[补充]
当你为每个调用该方法创建一个线程并且不使用状态中的任何内容时,为什么要使该方法同步?使该方法同步不会以任何方式限制线程的数量。在同步之前,可能存在上一个线程已经完成工作的机会。生成线程的过程可能会变慢。
但是,直到你发现真的有很多线程运行并且你正在耗尽内存之前,你应该继续使用它。如果你真的想在时间之前解决这个问题,那么你应该选择一些阻塞机制,比如Semaphore

我的方法在服务层内。您能详细说明一下...如何实现吗? - cometta
是的,确切地说。针对您的“如何”问题,我认为您需要展示相关的代码片段,并告诉我们为什么在这种情况下您担心线程安全性。我的意思是,是什么让您想到您的方法应该被同步或类似的事情。 - Adeel Ansari

3

我不确定这是否能回答您的问题,但是您可以在每封邮件中不要创建新线程且不要调用start方法,而是将Executor或者ExecutorService作为您类的成员变量,在实现时您可以使用一个ThreadPoolExecutor,并将其池大小设置为1。然后,您的sendMail方法将向执行器提交可运行对象。


3
另一个可能的方法是使用JMS队列,并将电子邮件发送代码放在消息驱动Bean中(或通过Spring JMS)。然后,您可以使用应用程序服务器来控制将使用多少并发实例的MDB,并以此方式限制传出电子邮件。

2

在Spring 3.0中,您可以使用@Async注释来执行任务,这样您的方法将在以后执行,并且该方法将直接返回,而无需等待电子邮件发送完成。

@Async
public  void sendThroughSMTP(List<String> emails,String subject,String content){
//Send emails here, you can directly send lots of email
}

在应用程序上下文中,您需要指定<task:annotation-driven/>,不要忘记为任务模式添加xmlns。

如果您想延迟执行一定时间,可以在方法中使用@Scheduled注释。

有关@Async和@Scheduled的更多教程,请访问此处:

http://blog.springsource.com/2010/01/05/task-scheduling-simplifications-in-spring-3-0/


我认为@Async是这里最好的解决方案之一。我曾经写过这个 http://www.skill-guru.com/blog/2010/01/13/asynchronous-method-invocation-in-spring-3-0/ - vsingh

2

将你的服务设置为singleton并在你的方法中添加synchronized


1

在您的情况下,Spring @Transactional 的使用不太正确。最好的选择是使用同步方法,并且如果您的方法被调用了数百次,则添加一些线程池。但我猜您在这里不需要线程池。

如果您使用线程发送批量电子邮件,那么同步方法有什么意义呢?如果一个进程调用您的方法并发送电子邮件,其他进程将调用您的方法,即使第一个发送电子邮件的进程尚未完成。

如果您想要限制电子邮件发送过程,您需要考虑使用队列(集合)并使用同步块保护该集合。创建另一个进程来监视该队列,如果队列中有一个项目,请弹出它并发送批量电子邮件,然后等待发送电子邮件进程完成并再次检查队列,如果队列中有任何项目,请继续发送电子邮件进程。如果队列中没有项目,请使监视线程睡眠一段时间,然后如果睡眠时间结束,请再次检查队列。


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