Java 同步方法还是使用 spring @transactional?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1950596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 01:43:15  来源:igfitidea点击:

synchronized method or use spring @transactional?

javaspringsynchronized

提问by cometta

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 ?

我有一种方法可以用来发送电子邮件。我想锁定此方法,以便每次只有一个线程可以访问它,其余线程同时合并。我应该同步方法还是使用 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();


}

采纳答案by Adeel Ansari

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, HibernateTransactionManagerall this is about database persistence. What will you configure for this email send out?

但是,我不明白 Spring 的事务管理如何适合这里。我的意思是Spring提供几个事务管理器,即DataSourceTransactionManagerJtaTransactionManagerHibernateTransactionManager这一切都是关于数据库的持久性。您将为发送的这封电子邮件配置什么?

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.

当您为每个对该方法的调用生成一个线程并且不使用 state 中的任何内容时,那么为什么要使 method synchronized. 使方法同步不会以任何方式限制线程数。由于同步,在开始新线程之前,前一个线程可能已经完成了工作,这可能是一种可能性。生成线程的过程可能会变慢。

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.

但是,您应该继续这样做,直到您发现确实有很多线程正在运行并且内存不足。如果你真的想提前解决这个问题,那么你应该选择一些阻塞机制,比如Semaphore

回答by pgras

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 Executoror ExecutorServiceas a member of your class, as an implementation you could use a ThreadPoolExecutorwith a pool size of 1. Your sendMail method would then submit Runnables to the executor.

我不确定它是否回答了您的问题,但是您可以将ExecutorExecutorService作为类的成员,而不是为每封邮件创建一个新线程并对其调用 start ,作为一种实现,您可以将ThreadPoolExecutor与池大小为 1。然后您的 sendMail 方法会将 Runnable 提交给执行程序。

回答by Ifnu

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.

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

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.

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

回答by beny23

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.

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

回答by Ifnu

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.

在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
}

then in application context you specify and don't forget to add xmlns for task schema.

然后在应用程序上下文中指定并且不要忘记为任务模式添加 xmlns。

If you want to delay the execution for certain amount of time, you may use @Scheduled annotation to your method.

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

Further tutorial about @Async and @Scheduled can be found here :

关于@Async 和@Scheduled 的更多教程可以在这里找到:

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

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

回答by user2601995

Make your service a singletonand add synchronizedto your method.

使您的服务成为一个singleton并添加synchronized到您的方法中。