同步方法还是使用 spring @transactional?
我有一个用于发送电子邮件的方法。我想锁定这个方法,这样每次只有一个线程可以访问它,其余的线程可以同时访问。我应该同步该方法还是使用 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();
}
I have a method that will be used to send out email. i want to lock this method so only one thread can accses it per time and the rest pool up concurrently. should i synchronized the method or use spring @transactional PROPAGATION_REQUIRED ?
in my service layer
//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();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
为什么不通过不使用任何实例级的东西来使方法线程安全?
然而,我不明白 Spring 的事务管理在这里如何适用。我的意思是Spring提供了一些事务管理器,即DataSourceTransactionManager,JtaTransactionManager,HibernateTransactionManager,所有这些都是关于数据库持久性的。您将为发送的这封电子邮件配置什么?
我相信,首先您应该向我们展示为什么您首先担心线程安全。您很可能想向我们展示一些相关的代码片段或其他内容。那么我们也许可以向您推荐一些东西。
[附录]
当您为该方法的每次调用生成一个线程并且不使用状态中的任何内容时,那么为什么要使该方法
同步
。使方法同步不会以任何方式限制线程数量。由于同步的原因,在启动新线程之前,前一个线程可能已经完成了工作。生成线程的过程可能会变慢。但是,您应该继续这样做,直到您发现确实有很多线程正在运行并且内存即将耗尽。如果你真的想提前解决这个问题,那么你应该选择一些阻塞机制,比如 信号量。
Why not make the method thread-safe by not using any instance level things?
However, I don't see how Spring's Transaction Management fits here. I mean Spring provides few transaction managers, i.e.
DataSourceTransactionManager
,JtaTransactionManager
,HibernateTransactionManager
all this is about database persistence. What will you configure for this email send out?I believe, first you should show us why you worry about the thread-safety in the first place. Most probably you would like to show us some relevant code snippet or something. Then we might be able to suggest you something.
[Addendum]
When you are spawning a thread for every call to that method and not using anything from the state, then why you want to make the method
synchronized
. Making the method synchronized will not limit the number of threads in any way. There might be chance that before starting a new thread, previous thread might have finished the work, because of synchronization. The process of spawning a thread might go slower.However, you should go with this until you find out that there are really many threads running and you are going out of memory. And if you really want to tackle that before time, then you should choose some blocking mechanism, something like Semaphore.
我不确定它是否回答了您的问题,但是您可以拥有 执行器 或 ExecutorService 作为类的成员,作为实现,您可以使用 ThreadPoolExecutor 池大小为 1。然后您的 sendMail 方法将提交 Runnables给执行人。
I'm not sure if it answers your question, but instead of creating a new thread for every mail and calling start on it you could have an Executor or ExecutorService as a member of your class, as an implementation you could use a ThreadPoolExecutor with a pool size of 1. Your sendMail method would then submit Runnables to the executor.
另一种可能性是使用 JMS 队列并将电子邮件发送代码放入消息驱动 Bean 中(或通过 Spring JMS)。然后,您可以使用应用程序服务器来控制将使用多少个 MDB 并发实例,并以此方式限制传出电子邮件。
Another possibility would be to use JMS queues and put the email sending code in a Message Driven Bean (or through Spring JMS). You can then use your app server to control how many concurrent instances of your MDB will be used and throttle the outgoing emails that way.
在Sping 3.0中,您可以使用@Async注解来执行任务,这样您的方法将稍后执行,并且直接返回该方法,而无需等待电子邮件发送。
然后在您指定的应用程序上下文中,不要忘记为任务架构添加 xmlns。
如果你想延迟执行一段时间,你可以在你的方法中使用@Scheduled注释。
有关@Async和@Scheduled的更多教程可以在这里找到:
http://blog.springsource.com/2010/01/05/task-scheduling-simplifications-in-spring-3-0/
in Sping 3.0 you can use @Async annotation to do task execution, so your method will be executed later and the method is returned directly without waiting for email to be sent.
then in application context you specify and don't forget to add xmlns for task schema.
If you want to delay the execution for certain amount of time, you may use @Scheduled annotation to your method.
Further tutorial about @Async and @Scheduled can be found here :
http://blog.springsource.com/2010/01/05/task-scheduling-simplifications-in-spring-3-0/
使您的服务成为
单例
,并将synchronized
添加到您的方法中。Make your service a
singleton
and addsynchronized
to your method.Spring @Transactional 在您的情况下使用不太正确。最好的选择是使用同步方法,如果您的方法被调用数百次,则添加一些线程池。但我想你在这里不需要线程池。
如果您使用线程发送群发电子邮件,那么同步该方法有什么意义呢?如果一个进程调用您的方法并发送电子邮件,即使第一个发送电子邮件进程尚未完成,其他进程也会调用您的方法。
如果您打算限制电子邮件发送过程,则需要考虑队列(集合)并使用同步块保护集合。创建另一个进程来监视该队列,如果队列中有一项,则将其弹出并发送群发电子邮件,然后等到发送电子邮件过程完成并再次检查队列,如果有任何项目,则继续发送电子邮件过程。如果队列中没有项目,则让监视器线程休眠一段时间,然后如果休眠时间完成,则再次检查队列。
Spring @Transactional is not quite correct used in your case. The best bet is using synchorized method and add some thread pooling if your method called by hundreds time. But i guess you dont need thread pool here.
If you use thread to send blast email, then what's point synchronizing the method? if one process call your method and send email, other process will call you method even the first sending email process not yet finish.
If you intent to throttle the email sending process, you need to condider a queue (collection) and protect the collection with synchronize block. Create another process to monitor that queue, if there is one item in queue, pop it and send blast email, then wait until sending email process finish and check again the queue, if there is any item, continue to sending email process. If no item in the queue, make the monitor thread sleep for some chunk of time, then if sleep time is finish check the queue again.