Spring MVC 单例线程安全?

发布于 2025-01-07 10:09:29 字数 727 浏览 4 评论 0原文

我有一个单例 Spring bean(默认范围)。因此,一个实例将被多个线程使用。然而,我对线程安全有点困惑,显然所有 Spring bean 如果它们是无状态的,那么它们都是线程安全的,但我的 bean 不是无状态的,它有每个请求/其他控制器/类使用的各种实例变量。

这是我的单例 bean 的开始:

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();
}

因此,上面的字段将由多个线程访问 - 将这些字段标记为 易失性 是否足够,或者我是否必须标记访问它们的方法(不仅有很多方法)这个类,还有其他控制器/类)与同步并使用等待/通知等?

非常感谢!

I have a singleton Spring bean (default scope). So, one instance will be used by multiple threads. However, I'm a bit confused with regards thread safety, apparently all Spring beans are thread safe if they are stateless, but my bean is not stateless, it has various instance variables which are used by each request/other controllers/classes.

Here is the beginning of my singleton bean:

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();
}

So, the fields above will be accessed by multiple threads - is it enough to mark these fields as volatile, or do I have to mark the methods which access them (there are a lot in not only this class, but other controllers/classes as well) with synchronized and use wait/notify etc?

Many thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

悸初 2025-01-14 10:09:29

Spring 本身确保在实例化、注入等之后正确发布您的 bean。这意味着任何引用您的单例 bean 的线程至少会看到其在 Spring 上下文创建结束时的状态。

如果状态是不可变的,那么你就没有什么可做的。

但是,如果单例的状态是可变的,则必须正确同步对此可变状态的访问。

Spring itself makes sure to properly publish your beans once they have been instantiated, injected, etc. This means that any thread having a reference to your singleton bean will at least see its state as it was at the end of the Spring context creation.

If the state is immutable, you don't have anything to do.

If the state of the singleton is mutable, you will have to properly synchronize the accesses to this mutable state, though.

白色秋天 2025-01-14 10:09:29

易失性没有帮助。它只会确保该值确实更新。

易失性意味着(http://www.javamex.com/tutorials/synchronization_volatile.shtml):

  • 该变量的值永远不会在线程本地缓存:所有读取和写入都将直接进入“主内存”;
  • 对变量的访问就像将其包含在同步块中一样,并对其自身进行同步。

仅当您的控制流在第一次写入和最后一次读取共享变量之间从不退出(外部)同步块,并且所有共享变量仅在使用同一锁对象的同步块内访问时,使方法同步才会有帮助。

所以一般的解决方案是在这种情况下防止共享变量。使类不可变的一种简单方法是使用局部变量和方法参数而不是共享实例变量。


您写道“如果 Spring bean 是无状态的,那么它们就是线程安全的,但我的 bean 不是无状态的。” ——好的,这个主题已在上面的段落中讨论过。

但从你的代码来看,这不是问题! 变量用 final 标记,因此它们是不可变的。如果该对象的字段以相同的方式运行(未更新或充分防止并发修改问题),则没有可变共享变量。有时这被称为“有效无状态”。这意味着这些值没有改变。所以这对于并发来说不是问题(因为并发问题是关于改变值的)。

最后:如果字段 (PcrfRecord...) 是有效无状态的,则您可以在不同线程中使用示例中的这个有效无状态类,而无需同步块。 (如果PcrfRecord字段...不是无状态的,那么PcrfSimulator类就不能被称为有效的无状态)——但这与Spring无关,很简单爪哇。

顺便说一句:如果你的变量是final,你不需要让它们volantile

volatile does not help. It would only make sure that the value is really updated.

Volatile means (http://www.javamex.com/tutorials/synchronization_volatile.shtml):

  • The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory";
  • Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself.

Making the method synchronized will only help if your control flow never exit the (outer) synchronized block between the first write and the last read to the shared variables, and all shared variables are only accessed within synchronized blocks that use the same lock object.

So the general solution is to prevent shared variables in this scenario. One easy way to make the class immutable is to use local variables and method parameters instead of shared instance variables.


You wrote "Spring beans are thread safe if they are stateless, but my bean is not stateless." -- Ok that theme is discussed in the paragraph above.

But in from your code is seams that this is not the problem! The variables marked with final so they are immutable. If the fields of that object behaves in the same way (are not updated or are adequate protected against concurrent modification problems) you do not have mutable shared variables. Sometimes this is called "effective stateless". This means the values are not changed. So this is no problem for concurrency, (because the concurrency problem is about changing values).

In the end: You can use this effective stateless class from the example in different threads without a synchronized block if the fields (PcrfRecord...) are effective stateless. (If the fields PcrfRecord... are not stateless then the class PcrfSimulator can not been called effective stateless) -- But this has noting to to with Spring, it is plain Java.

Btw: if your variable is final you do not need to make them volantile.

瞳孔里扚悲伤 2025-01-14 10:09:29

如果您在初始化后将其标记为上下文中的单例,则您的类将不是线程安全的
手动使用“new”字段,该字段在创建 bean 时发生一次,并且您将在内存中拥有一个实例(如您的单例),因此,您的线程共享 CustomGxSessionIdCacheImpl、PcrfRecord 等的实例。

如果您可以使这些实例受到 spring 上下文的控制,例如:

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

并在 PcrfSimulator 中自动装配它们,例如:

@Autowired
private final CustomGxSessionIdCacheImpl gxSessionIdCache

之后,一旦您的代码访问 gxSessionIdCache,spring 就会分别为每次访问和每个线程创建一个新实例。 Singleton 中的任何其他方法都必须用 synchronized 标记,因为这些方法是开放用于多线程访问的。 Spring 单例是常规单例。

我认为,如果根本没有状态,那么一切都是线程安全的,这种说法是错误的。如果你考虑底层,方法也有状态,即局部变量,如果多个线程访问这些,你也会感到头痛。

Your class won't be thread-safe, if you mark it as singleton in context since you initialize
the fields with "new" manually which happens once as the bean is created and of which you will have one instance in memory like your singleton and accordingly, your threads share the instance of CustomGxSessionIdCacheImpl, PcrfRecord and so on.

If you can make these instances take under control of spring context, like:

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

and autowire them in PcrfSimulator like:

@Autowired
private final CustomGxSessionIdCacheImpl gxSessionIdCache

after that, as soon as your code access on gxSessionIdCache, spring creates a new instance for each access and for each thread respectively. Any other methods in Singleton had to be marked with synchronized since these are open for multi-thread acceess. Spring singletons are regular singletons.

I think, it is wrong to say, if you have no state at all, then everything is thread-safe. If you think low-level, the methods have also states, i.e. local variables, and if multiple threads access these, you can get also a headache.

未蓝澄海的烟 2025-01-14 10:09:29

正如已经确定的那样,您的类不是线程安全的。原型范围是一种方法,但如果原型范围的 bean 自动装配到单例 bean 中,它仍然意味着只创建原型 bean 的一个实例,从而有效地使其成为单例。

同步是另一种方法,但这实际上仅适用于实例变量意味着在线程之间共享的情况。但是,如果目的是实例变量对于每个线程来说应该是唯一的,那么您应该查看ThreadLocal 代替。

As has been established already, your class is not thread-safe. Prototype-scope is one way to go, but if a prototype-scoped bean is autowired into a singleton bean, it will still mean that only one instance of the prototype bean is created, effectively making it singleton as well.

Synchronization is another way to go, but that really only applies if the instance variables are meant to be shared between threads. If, however, the intention is that the instance variables should be unique to each thread, you should look at ThreadLocal instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文