这个Spring单例bean线程的设计是安全的吗?

考虑以下Spring Service类。 定义的弹簧范围是Singleton。 自动连接的两个服务bean作为下面类中的字段具有相似的结构 – 它们也由以下任一字段组成

  • 春豆本身
  • 无国籍class
  • 不可变类

等等。 此模式总体上用于应用程序设计中。

@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 

说DocumentService类是不可变的是正确的,因为它不可能改变它的两个字段中的任何一个(它们是只能由容器本身初始化一次的spring bean)?

在任何情况下,上面定义的DocumentService bean都可以被认为是线程安全的吗? 如果遵循这个设计,整个应用程序也是线程安全的吗?

说DocumentService类是不可变的是正确的,因为它不可能改变它的两个字段中的任何一个(它们是只能由容器本身初始化一次的spring bean)?

根据不变性的定义 ,并且从forms上讲,这个类不是不可变的

如果无法更改对象的状态,则对象是不可变的,而documentGenerationServicedocumentPublishService 的状态是 DocumentService 类的状态的一部分

并且,因此, 如果类始终具有相同的状态,则其行为始终相同 。 换句话说,没有办法改变不可变对象的行为,因为对象的行为只取决于它的状态,而在不可变对象中,这个状态永远不会改变(不可变对象的例子是字符串和整数)。

请注意,在不变性的定义中,我们发现一个例外,即“ 即使某些属性发生变化,但对象的状态 [和因此行为] 似乎是不变的[…] ”,“ 对象被认为是不可变的 ”,但是在这种情况下(提供的信息),引用状态的改变肯定会改变类的行为(因为我们对它们自己的内部状态没有任何控制)。

有一种策略可以使类不可变。 你已经遵循了它的一些指导原则,但是如果你希望这样做是不可变的(我认为情况并非如此)你需要其他一些像你在构造函数中获得的参数的“防御性复制”避免子类重写方法

这个链接也很有趣。

不过, 你不应该让Spring bean不可变,因为它不是使用Spring提供的编程模型的方法。 因此,在这种情况下,该类不是不可变的“好”。

在任何情况下,上面定义的DocumentService bean都可以被认为是线程安全的吗?

如此处所声明的,此类是IS线程安全的 。 许multithreading可以安全地访问此类,而不会出现任何竞争条件。 我们不能对它包含的字段说同样的内容,但这个类是线程安全的。 这与“线程安全列表”的工作方式相同:它可以包含“无线程安全”对象,但仍然是“线程安全列表”。

如果遵循这个设计,整个应用程序也是线程安全的吗?

如果系统的所有类都是线程安全的(即不会出现单个竞争条件),您可以非正式地说应用程序是线程安全的。

Spring不保证线程安全。 那是你的责任。

所有私有成员变量都是共享的。 它们可能是最终的,但这只意味着引用无法更改。 任何可变状态都必须同步。 如果它们确实是不可改变的,那么我认为你是坚实的。

我同意有关自动assembly依赖关系的评论。 如果可能的话,我会把那些受Spring控制的人留下。

您可以将@Autowired注释放在服务之上,而不是在构造函数中使用它们。 它是一个Spring托管bean,这意味着它是一个单例。 它是线程安全的,但这取决于实现。

 @Service public class DocumentService { @Autowired private DocumentGenerationService documentGenerationService; @Autowired private DocumentPublishService documentPublishService; ... methods follow 

您的问题中显示的示例代码绝对是线程安全的。

但是,需要在整个应用程序的上下文中考虑代码。 例如,上面的代码不提供有关documentGenerationServicedocumentPublishService属性引用的对象的线程安全性的任何保证。 如果它们没有充分同步,那么使用它们的代码(包括此类的其他方法)可能不是线程安全的。

您的代码看起来是线程安全的。 当它说豆子是单身时,Spring不保证线程安全。 如果在spring中创建singleton范围的bean,它只是意味着每个Spring IoC容器创建一个对象实例。 但是,单例范围的bean类本身可能不是线程安全的,因此程序员有责任使代码线程安全。

在您的代码中, documentGenerationService例如是final。 这保证了引用不会改变,并且从新的Java Memory模型中也可以保证实例化。 但@duffymo说,被引用的对象也必须是不可变的。

rest一切都很好:)

当它说豆子是单身时,Spring不保证线程安全。 如果在spring中创建singleton范围的bean,它只是意味着每个Spring IoC容器创建一个对象实例。 但是,单例范围的bean类本身可能不是线程安全的,因此程序员有责任使代码线程安全。