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

时间:2011-06-21 01:24:35

标签: java multithreading spring concurrency singleton

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

  • 春豆本身
  • 无国籍班级
  • 不可变的课程

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

@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都可以被认为是线程安全的吗?如果遵循这种设计,整个应用程序也是线程安全的吗?

6 个答案:

答案 0 :(得分:20)

  

说DocumentService类是不可变的是正确的,因为它不可能改变它的两个字段中的任何一个(可以通过容器本身只初始化一次的spring bean)吗? < / p>

根据definition of immutability,正式来说,这个课程不是一成不变的

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

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

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

有一个 strategy 来使类不可变。你已经遵循了它的一些指导原则,但如果你希望这样做是不可改变的(我认为情况并非如此)你需要其他一些如你所收到的论据的“防御性复制”在构造函数中,避免子类重写方法

link也很有趣。

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

  

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

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

  

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

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

答案 1 :(得分:4)

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

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

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

答案 2 :(得分:2)

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

@Service     
public class DocumentService {  

  @Autowired
  private DocumentGenerationService documentGenerationService;

  @Autowired
  private DocumentPublishService documentPublishService;

... methods follow

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

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

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

休息一切都很好:)。

答案 5 :(得分:0)

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