2016-06-12 238 views
1

我使用Spring的JavaMailSenderImpl在我的Web應用程序中發送電子郵件。我只創建了一個這樣的實例(實際上它被另一個使用spring bean創建的對象使用,並且是一個單例)。是JavaMailSenderImpl的spring線程安全嗎?

所以問題是,JavaMailSenderImpl是線程安全的嗎?在我的應用程序中,當多個線程同時使用mailSender時,它是否會導致任何競爭條件?

+0

是的,它一旦構建就是線程安全的。 –

+0

@ M.Deinum我以爲看着源代碼也是一樣,但我不確定。請你詳細說明並添加一個答案,以便我可以接受它。如果你解釋多個線程可以同時發送郵件,那將是非常好的。 – kiran

回答

3

是的JavaMailSenderImpl是線程安全的一旦它被構造。看看doSend做的實際工作。它只包含方法局部變量(因此每個調用線程/堆棧都有自己的實例)。 (這同樣適用於添加一些功能的send方法)。

getSession這樣的方法是​​,所以只有一個線程可以訪問該方法。

使其線程安全的最大的事情是存在(幾乎)沒有可變共享狀態和單個可變共享狀態(Session),這是​​。

除此之外,它已經以單例方式在生產系統中使用了12年以上,並且從來沒有任何併發​​問題。是的,我們在高度併發的應用程序中使用它。 (而且它也是Spring Batch和Spring Integration等其他框架組件使用API​​的方式)。

+0

但看看[字段加載]的順序(https://github.com/spring-projects/spring-framework/blob/master/spring-context-support/src/main/java/org /springframework/mail/javamail/JavaMailSenderImpl.java#L491)。用戶名和密碼在'getSession'調用之前加載,所以即使在結構之後存在某個同步點時,這裏也沒有發生。 – SerCe

+0

正確...但是這是你不應該做的第一件事...而且我聲明使用AFTER構建是安全的... Spring在單線程中引導。另外'getUsername'和'getPassword'被調用一次,之後在本地不使用全局。這同樣適用於框架的其他類(它們都包含一個註釋:**該類的一個實例在配置完成後是線程安全的。**。)。 –

+0

@ m-deinum,但'connectTransport'可以從不同的線程(每個'doSend')多次調用。因此,如果該線程在spring-bootstrap線程之前啓動,由於缺少happen-before邊緣,它可以從'getUsername'中讀取null。 (我同意你這是非常不切實際的情況,特別是對於x86,但是我看不到這裏有任何JMM證明正確性的證明) – SerCe

0

不,它不是。

雖然it has在其源代碼,字段如用戶,密碼的某些同步沒有同步訪問。因此,如果您在一個線程中調用setUsername,則其他線程不可見。

+0

我僅使用spring創建對象一次,併爲郵件服務器身份驗證和javaMailProperties設置所有必填字段。我不會再改變這些。一旦創建了對象,多個線程(jetty)就會使用它並行發送郵件。這會成爲一個問題嗎?我具體詢問郵件發送部分。 – kiran

+0

[這裏](https://github.com/spring-projects/spring-framework/blob/master/spring-context-support/src/main/java/org/springframework/mail/javamail/JavaMailSenderImpl.java#sourcegraph&def = JavaArtifact/org.springframework/spring-context-support/-/org/springframework/mail/javamail/JavaMailSenderImpl:type/getSession&L151-156),getters在第一個同步點之前被調用,所以根據發生 - 線程安全, – SerCe