java Spring单例bean的这种设计线程安全吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6419393/
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
Is this design of Spring singleton beans thread safe?
提问by haps10
Consider the following Spring Service class. The spring scope defined is Singleton. The two service beans auto-wired as fields in the class below have similar structure - they too are composed of fields which are either of the following
考虑以下 Spring Service 类。定义的 spring 范围是 Singleton。在下面的类中自动连接为字段的两个服务 bean 具有相似的结构 - 它们也由以下任一字段组成
- Spring beans themselves
- stateless classes
- immutable classes
- 春豆本身
- 无状态类
- 不可变类
and so on. This pattern is overall used in the application design.
等等。这种模式在应用程序设计中普遍使用。
@Service
public class DocumentService {
private final DocumentGenerationService documentGenerationService;
private final DocumentPublishService documentPublishService;
@Autowired
public DocumentService (DocumentGenerationService documentGenerationService,
DocumentPublishService documentPublishService) {
this.documentGenerationService = documentGenerationService;
this.documentPublishService = documentPublishService;
}
... methods follow
Is it correct to say that the DocumentService class is immutable since it's not possible to mutate any of its two fields (which are spring beans that can be initialized only once by the container itself)?
说 DocumentService 类是不可变的是否正确,因为它不可能改变它的两个字段中的任何一个(它们是只能由容器本身初始化一次的 spring bean)?
In any case, can the DocumentService bean as defined above be considered thread-safe? And if this design is followed the application as a whole is thread-safe too?
在任何情况下,上面定义的 DocumentService bean 是否可以被认为是线程安全的?如果遵循这种设计,整个应用程序也是线程安全的吗?
采纳答案by Mr.Eddart
Is it correct to say that the DocumentService class is immutable since it's not possible to mutate any of its two fields (which are spring beans that can be initialized only once by the container itself)?
说 DocumentService 类是不可变的是否正确,因为它不可能改变它的两个字段中的任何一个(它们是只能由容器本身初始化一次的 spring bean)?
According to the definition of immutability, and formally speaking, this class is NOT immutable.
根据immutability的定义,正式地说,这个类不是 immutable。
An object is immutable if it is not possible to change the state of the object, and the state of documentGenerationService
and documentPublishService
is part of the state of the classDocumentService
.
一个目的是不可变的,如果它不能够改变对象的状态,并且状态documentGenerationService
和documentPublishService
是类的状态的一部分DocumentService
。
And, as a result, if the class has alwaysthe same state, it behaves alwaysthe same way. In other words, there is no way to change the behaviour of an immutable object because the behaviour of an object depends only in its state, and in an immutable object, this state never changes (examples of immutable objects are Strings and Integers).
并且,因此,如果类始终具有相同的状态,则它的行为方式始终相同。换句话说,没有办法改变不可变对象的行为,因为对象的行为只取决于它的状态,而在不可变对象中,这种状态永远不会改变(不可变对象的例子是字符串和整数)。
Note that in the definition of immutability we find an exception where "an object is considered immutable even if some [...] attributes change but the object's state[and, therefore, behaviour] appears to be unchanging [...]", but in this case (with the information provided) a change in the state of the references could definitely change the behaviour of the class (since we don't have any control on their own internal state).
请注意,在不变性的定义中,我们发现了一个例外,其中“即使某些 [...] 属性发生变化,但对象的状态[以及因此,行为]似乎没有变化 [...]”,对象也被认为是不可变的,但在这种情况下(根据提供的信息),引用状态的变化肯定会改变类的行为(因为我们无法控制它们自己的内部状态)。
There is a strategyto make a class immutable. You already follow some of its guidelines, but in case you wished to do it immutable (I think it is not the case) you would need some others like make "defensive copy"of the arguments that you receive in the constructor and avoid subclasses overriding methods.
有一种使类不可变的策略。你已经遵循了它的一些指导方针,但如果你希望它不可变(我认为事实并非如此)你需要一些其他的,比如对你在构造函数中收到的参数进行“防御性复制”,并避免子类覆盖方法。
This linkis also interesting.
这个链接也很有趣。
Nevertheless, you should notmake Spring beans immutable, since it is not the way to use the programming model that Spring offers. So, in this case, it is "good" that the class is not immutable.
尽管如此,您不应该使 Spring bean 不可变,因为这不是使用 Spring 提供的编程模型的方式。因此,在这种情况下,类不是一成不变是“好”的。
In any case, can the DocumentService bean as defined above be considered thread-safe?
在任何情况下,上面定义的 DocumentService bean 是否可以被认为是线程安全的?
As declared here, this class IS thread safe. Many threads can safely access this class without any race condition arising. We cannot say the same about the fields it contains, but this class is thread-safe. This works just the same way as "thread-safe list": it can contain "no thread-safe" objects, but still be a "thread-safe list".
正如这里所声明的,这个类是线程安全的。许多线程可以安全地访问此类,而不会出现任何竞争条件。我们不能对它包含的字段说同样的话,但这个类是线程安全的。这与“线程安全列表”的工作方式相同:它可以包含“非线程安全”对象,但仍然是“线程安全列表”。
And if this design is followed the application as a whole is thread-safe too?
如果遵循这种设计,整个应用程序也是线程安全的吗?
If all the classes of your system are thread-safe (i.e. not a single race condition appears anywhere) you could informallysay that the application is thread safe.
如果您系统的所有类都是线程安全的(即没有任何地方出现单个竞争条件),您可以非正式地说应用程序是线程安全的。
回答by duffymo
Spring doesn't guarantee thread-safety. That's your responsibility.
Spring 不保证线程安全。那是你的责任。
All private member variables are shared. They might be final, but that only means that the references can't be changed. Any mutable state must be synchronized. If they're indeed immutable, then I think you're on solid ground.
所有私有成员变量都是共享的。它们可能是最终的,但这仅意味着无法更改引用。任何可变状态都必须同步。如果它们确实是一成不变的,那么我认为您是有根据的。
I agree with the comment about autowiring dependencies. I would leave those under Spring's control if possible.
我同意关于自动装配依赖项的评论。如果可能的话,我会将它们置于 Spring 的控制之下。
回答by Stephen C
The example code shown in your question is definitely thread-safe.
您的问题中显示的示例代码绝对是线程安全的。
However, the code needs to be considered in the context of the whole application. For instance, the code above does not provide any guarantees about the thread safety of the objects referred to by the documentGenerationService
and documentPublishService
attributes. If they are not adequately synchronized, then code that uses them (including other methods of this class) may not be thread-safe.
但是,需要在整个应用程序的上下文中考虑代码。例如,上面的代码不提供关于documentGenerationService
和documentPublishService
属性引用的对象的线程安全性的任何保证。如果它们没有充分同步,那么使用它们的代码(包括此类的其他方法)可能不是线程安全的。
回答by telm
You can put the @Autowired annotation on top of the services instead of using them in the constructor. It's a Spring managed bean which means it's a singleton. It is thread safe, but that depends on the implementation.
您可以将 @Autowired 注释放在服务之上,而不是在构造函数中使用它们。它是一个 Spring 管理的 bean,这意味着它是一个单例。它是线程安全的,但这取决于实现。
@Service
public class DocumentService {
@Autowired
private DocumentGenerationService documentGenerationService;
@Autowired
private DocumentPublishService documentPublishService;
... methods follow
回答by kinshuk4
Your code looks thread-safe. Spring doesn't guarantee thread-safety, when it says beans are singleton. If you make bean of singleton scope in spring, it simply mean that a single object instance per Spring IoC container is created. But still that singleton-scoped bean class may not be thread safe in itself, so its programmer's responsibility to make the code thread safe.
您的代码看起来是线程安全的。Spring 不保证线程安全,当它说 bean 是单例时。如果你在 spring 中创建单例作用域的 bean,它仅仅意味着每个 Spring IoC 容器创建了一个对象实例。但是那个单例范围的 bean 类本身可能不是线程安全的,所以它的程序员有责任使代码线程安全。
In your code, documentGenerationService
for instance is final. That guarantees that references cannot change, and also from new Java Memory model, instantiation is guaranteed. But @duffymo said, the objects being referred must be immutable as well.
在您的代码中,documentGenerationService
例如是最终的。这保证了引用不会改变,并且从新的 Java 内存模型中,也保证了实例化。但是@duffymo 说,被引用的对象也必须是不可变的。
Rest all is good :)
休息一切都很好:)
回答by user1865328
Spring doesn't guarantee thread-safety, when it says beans are singleton. If you make bean of singleton scope in spring, it simply mean that a single object instance per Spring IoC container is created. But still that singleton-scoped bean class may not be thread safe in itself, so its programmer's responsibility to make the code thread safe.
Spring 不保证线程安全,当它说 bean 是单例时。如果你在 spring 中创建单例作用域的 bean,它仅仅意味着每个 Spring IoC 容器创建了一个对象实例。但是那个单例范围的 bean 类本身可能不是线程安全的,所以它的程序员有责任使代码线程安全。