Является ли JavaMailSenderImpl потокобезопасным?

Я использую JavaMailSenderImpl с весны для отправки электронных писем в своем веб-приложении. Я создал только один экземпляр этого (на самом деле он используется другим объектом, созданным с использованием спринг-бинов и являющимся синглтоном).

Итак, вопрос в том, является ли JavaMailSenderImpl потокобезопасным? В моем приложении, когда несколько потоков одновременно используют mailSender, приведет ли это к каким-либо условиям гонки?


person kiran    schedule 12.06.2016    source источник
comment
Да, он является потокобезопасным после создания.   -  person M. Deinum    schedule 13.06.2016
comment
@M.Deinum M.Deinum Я думал так же, глядя на исходный код, но не уверен. не могли бы вы уточнить и добавить ответ, чтобы я мог его принять. Будет здорово, если вы объясните, как несколько потоков могут отправлять почту одновременно.   -  person kiran    schedule 13.06.2016


Ответы (3)


Да, JavaMailSenderImpl является потокобезопасным после создания.

Взгляните на doSend метод, который выполняет реальную работу. Он содержит только локальные переменные метода (поэтому каждый вызывающий поток/стек имеет свой собственный экземпляр). (То же самое относится и к методу send, который добавляет некоторую функциональность).

Такие методы, как getSession равно synchronized, поэтому только один поток может иметь доступ к этому методу.

Самое главное, что делает его потокобезопасным, — это тот факт, что (почти) нет изменяемого общего состояния, а единственное изменяемое общее состояние (Session), которое есть, — это synchronized.

Кроме того, я использовал его более 12 лет в производственных системах в одноэлементном режиме и никогда не имел проблем с параллелизмом. И да, мы использовали его в высокопараллельных приложениях. (И это также то, как другие компоненты платформы, такие как Spring Batch и Spring Integration, используют JavaMailSender API).

person M. Deinum    schedule 13.06.2016
comment
Но взгляните на порядок загрузка поля. Имя пользователя и пароль загружаются перед вызовом getSession, поэтому здесь не происходит «до края», даже если существует некоторая точка синхронизации после построения. - person SerCe; 13.06.2016
comment
Правильно... Но это то, что вы не должны делать в первую очередь... И я заявляю, что безопасно использовать ПОСЛЕ построения... Spring загружается в один поток. Также getUsername и getPassword вызываются один раз, а затем используются локально, а не глобально. То же самое относится и к другим классам фреймворка (все они содержат примечание: ** Экземпляр этого класса является потокобезопасным после настройки. **.). - person M. Deinum; 13.06.2016
comment
@m-deinum, но connectTransport можно вызывать несколько раз из разных потоков (каждое doSend). Таким образом, если этот поток запустился до потока Spring-Bootstrap, он может прочитать null из getUsername из-за отсутствия края «происходит до». (Я согласен с вами, что это очень непрактичный случай, особенно для x86, но я не вижу здесь никаких доказательств правильности JMM) - person SerCe; 13.06.2016
comment
Ну и что... Транспорт не кешируется, он пересоздается при каждом вызове. Поток, который это делает, вероятно, получит исключение, которое не может отправить электронное письмо. Транспорт воссоздается для каждого вызова doSend. - person M. Deinum; 13.06.2016
comment
Кроме того, вы не можете получить экземпляр bean-компонента до того, как Spring его инициализирует, если только вы сами не создаете новые экземпляры. Таким образом, Spring уже должен быть загружен, прежде чем вы сможете получить доступ к экземпляру. И объект, который ссылается на bean-компонент, гарантированно получит инициализированный bean-компонент. Поэтому, если после этого вы не возитесь с именами пользователей и паролями, использование его обычным способом из контекста Spring делает его в основном потокобезопасным. - person M. Deinum; 13.06.2016
comment
Это правда. Вы можете получить доступ к объекту только после того, как пружина его инициализирует. Когда у меня есть объект, я не буду с ним возиться. Я использую его только для отправки писем. Думаю, это решит мою проблему. Спасибо!! - person kiran; 13.06.2016

Он потокобезопасен, но стоит добавить, что он может поддерживать только ограниченное количество одновременных вызовов. Я получаю следующую ошибку, когда мой 4-й поток вызывает функцию sendMail:

org.springframework.mail.MailSendException: Неудачные сообщения: com.sun.mail.smtp.SMTPSendFailedException: 432 4.3.2 STOREDRV.ClientSubmit; превышен предел потока отправителя [Hostname=***]. Таким образом, вы должны перехватывать исключения во время выполнения и регистрировать их, иначе они просто будут проглочены службой-исполнителем, выполняющей этот поток.

person saurabh.in    schedule 11.10.2019

Нет.

Хотя имеет некоторую синхронизацию в исходном коде, такие поля, как пользователь, пароли, не имеют доступа к синхронизации. Итак, если вы вызываете setUsername в одном потоке, нет гарантии видимости для других потоков.

person SerCe    schedule 12.06.2016
comment
Я создаю объект только один раз, используя spring и устанавливая все необходимые поля для аутентификации почтового сервера и javaMailProperties. Я не буду менять их снова. После создания объекта несколько потоков (причал) используют его для параллельной отправки почты. Будет ли это проблемой? Я специально спрашиваю о части отправки почты. - person kiran; 12.06.2016
comment
Здесь геттеры вызываются перед первой синхронизацией точка, так что в зависимости от того, что происходит, прежде чем это не будет потокобезопасным, - person SerCe; 12.06.2016