Spring MVC Singleton поток безопасности? - PullRequest
6 голосов
/ 21 февраля 2012

У меня есть Singleton Spring bean (область по умолчанию). Таким образом, один экземпляр будет использоваться несколькими потоками. Тем не менее, я немного запутался в отношении безопасности потоков, по-видимому, все бины Spring являются потокобезопасными, если они не сохраняют состояние, но мой компонент не является состоянием без состояния, у него есть различные переменные экземпляра, которые используются каждым запросом / другими контроллерами / классами.

Вот начало моего синглтон-бина:

public class PcrfSimulator {

private final CustomGxSessionIdCacheImpl gxSessionIdCache = new CustomGxSessionIdCacheImpl();
private final PcrfRecord pcrfRec = new PcrfRecord();
private final ResponseConditions responseConditions = new ResponseConditions();

public CustomGxSessionIdCacheImpl getGxSessionIdCache() {
    return gxSessionIdCache;
}

public ArrayList<Rule> getRules() {
    return pcrfRec.getRules();
}

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

Большое спасибо!

Ответы [ 4 ]

3 голосов
/ 21 февраля 2012

Spring сам по себе гарантирует правильную публикацию ваших bean-компонентов после того, как они были созданы, внедрены и т. Д. Это означает, что любой поток, имеющий ссылку на ваш одиночный bean-компонент, по крайней мере увидит свое состояние таким, каким оно было в конце контекста Spring.создание.

Если штат неизменен, вам нечего делать.

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

3 голосов
/ 21 февраля 2012

volatile не помогает. Было бы только убедиться, что значение действительно обновлено.

Летучие средства (http://www.javamex.com/tutorials/synchronization_volatile.shtml):

  • Значение этой переменной никогда не будет кэшироваться локально: все операции чтения и записи будут идти прямо в «основную память»;
  • Доступ к переменной действует так, как будто она заключена в синхронизированный блок и синхронизирована сама по себе.

Синхронизация метода поможет только в том случае, если ваш поток управления никогда не выходит из (внешнего) синхронизированного блока между первой записью и последним чтением общих переменных, а все общие переменные доступны только в синхронизированных блоках, которые используют одну и ту же блокировку. объект.

Таким образом, общее решение состоит в том, чтобы предотвратить использование общих переменных в этом сценарии. Один простой способ сделать класс неизменным - это использовать локальные переменные и параметры метода вместо общих переменных экземпляра.


Вы писали: «Весенние бобы являются поточно-ориентированными, если они не имеют состояния, но мой боб не является государством». - Хорошо, эта тема обсуждается в параграфе выше.

Но из вашего кода кажется, что это не проблема! Переменные, отмеченные final, поэтому они неизменны. Если поля этого объекта ведут себя одинаково (не обновляются или адекватно защищены от одновременных проблем модификации), у вас нет изменяемых общих переменных. Иногда это называется «эффективным лицом без состояния» . Это означает, что значения не изменены. Так что это не проблема для параллелизма (потому что проблема параллелизма заключается в изменении значений).

В конце: Вы можете использовать этот эффективный класс без сохранения состояния из примера в разных потоках без синхронизированного блока, если поля (PcrfRecord ...) являются эффективными без сохранения состояния. (Если поля PcrfRecord ... не являются без сохранения состояния, класс PcrfSimulator нельзя назвать эффективным без сохранения состояния) - Но это имеет отношение к Spring, это просто Java.

Кстати: если ваша переменная final, вам не нужно делать их volantile.

0 голосов
/ 21 февраля 2012

Как уже было установлено, ваш класс не является потокобезопасным. Prototype-scope - это один из способов, но если bean-объект с прототипом автоматически подключается к одноэлементному bean-компоненту, это все равно будет означать, что создан только один экземпляр bean-компонента-прототипа, что фактически делает его также одиночным.

Синхронизация - это еще один способ, но он действительно применим, только если переменные экземпляра означают для совместного использования между потоками. Однако, если предполагается, что переменные экземпляра должны быть уникальными для каждого потока, вместо этого вы должны взглянуть на ThreadLocal.

0 голосов
/ 21 февраля 2012

Ваш класс не будет потокобезопасным, если вы пометите его как одноэлементный в контексте с момента инициализации поля с пометкой "new" вручную, что происходит один раз при создании бина, и из которых у вас будет один экземпляр в памяти, такой как ваш синглтон, и, соответственно, ваши потоки совместно используют экземпляр CustomGxSessionIdCacheImpl, PcrfRecord и так далее.

Если вы можете заставить эти экземпляры взять под контроль контекст весны, как:

<bean id="customGxSessionIdCache" class="package.CustomGxSessionIdCacheImpl" scope="prototype">

и автоматически связать их в PcrfSimulator, например:

@Autowired
private final CustomGxSessionIdCacheImpl gxSessionIdCache

после этого, как только ваш код получит доступ к gxSessionIdCache, Spring создаст новый экземпляр для каждого доступа и для каждого потока соответственно. Любые другие методы в Singleton должны были быть помечены synchronized, так как они открыты для многопоточного доступа. Весенние синглтоны - это обычные синглтоны.

Я думаю, неправильно говорить, что если у вас вообще нет состояния, значит, все поточно-ориентировано. Если вы думаете о низком уровне, методы также имеют состояния, то есть локальные переменные, и если к ним обращаются несколько потоков, вы также можете испытывать головную боль.

...