微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如果在Spring Framework的@PostConstruct中初始化对象属性,是否应该将对象属性标记为volatile?

如何解决如果在Spring Framework的@PostConstruct中初始化对象属性,是否应该将对象属性标记为volatile?

Spring框架与Java编程语言无关,它只是一个框架。因此,通常,您需要将不同线程访问的非final字段标记volatile。归根结底,Spring bean只不过是Java对象,所有语言规则都适用。

final使用Java编程语言对字段进行特殊处理。亚历山大Shipilev,在 Oracle的性能的家伙写了一大篇关于此事。简而言之,当构造函数初始化final字段时,用于设置字段值的程序集会添加一个附加的内存屏障,以确保任何线程都能正确看到该字段。

对于非final字段,不会创建此类内存屏障。因此,通常,@postconstruct-annotated方法很可能会初始化该字段,并且另一个线程不会看到此值,或者更糟的是,在构造函数仅部分执行时看到该值。

这是否意味着您始终需要将非final字段标记为易失性?

简而言之,是的。如果一个字段可以由不同的线程访问,则可以。不要犯与我只想了几秒钟(感谢Jk1进行更正)并考虑Java代码的执行顺序有关的错误。您可能会认为您的Spring应用程序上下文是在单个线程中引导的。这意味着引导线程将不会对非易失性字段产生问题。因此,您可能会认为一切正常,只要您不将应用程序上下文公开给另一个线程,直到它完全初始化即可,即调用带注释的方法。这样想,您可以假设,其他线程只要没有在引导后更改字段,就没有机会缓存错误 字段值。

相反,允许编译后的代码对指令进行重新排序,即,即使@postconstruct在相关bean暴露给Java代码中的另一个线程之前调用- annotated方法,也不一定会在编译后的代码中保留这种 巧合之前的 关系。运行。因此,另一个线程可能 始终 读取并缓存该非volatile字段,而该非字段甚至还没有被完全初始化,甚至被部分初始化。这可能会引入一些细微的错误,不幸的是,Spring文档并未提及此警告。JMM的这些细节是我个人更喜欢final字段和构造函数注入的原因。

:根据另一个问题的答案,在某些情况下,未将字段标记volatile仍会产生有效结果。我对此进行了进一步的研究,事实上Spring框架保证了一定数量事情发生- 开箱即用的安全性。看看JLS的事前发生关系,其中明确指出:

监视器上的解锁发生在该监视器上的每个后续锁定之前。

Spring框架利用了这一点。所有bean都存储在一个映射中,并且每次在该映射中注册或检索bean时,Spring都会获取一个特定的监视器。结果,在注册完全初始化的bean之后,同一监视器将被解锁,并在从另一个线程检索同一bean之前将其锁定。这迫使另一个线程遵守Java代码的执行顺序所反映的事前发生 关系。因此,如果您一次引导您的bean,则所有访问完全初始化的bean的线程都将看到此状态,只要它们以规范的方式访问该bean(即通过查询应用程序上下文或自动编写来进行显式检索)。例如,@postconstruct即使不声明字段,也可以保证二传手注入或方法的使用安全volatile。实际上,因此您应该避免使用volatile字段,因为它们会为每次读取引入运行时开销,从而导致在循环访问字段时会感到痛苦,并且由于关键字表示错误的意图。(顺便说一句,据我所知,Akka框架采用了类似的策略,其中除Spring之外,Akka在此问题上有所保留。)

但是,此保证仅用于在引导程序之后对Bean的检索。如果volatile在引导后更改了非字段,或者在初始化期间泄漏了bean引用,则该保证不再适用。

请查看此较早的博客条目,该条目进一步详细描述了此功能。显然,该功能并未得到记录,因为即使Spring人士也知道(但是很长时间没有做任何事情)。

解决方法

假设我在Spring单例bean @PostConstruct(简化代码)中进行了一些初始化:

@Service
class SomeService {
  public Data someData; // not final,not volatile

  public SomeService() { }

  @PostConstruct
  public void init() {
     someData = new Data(....);
  }
}

我应该担心someData其他豆的可见性并对其进行标记volatile吗?

(假设我无法在构造函数中初始化它)

第二种情况:如果我 覆盖 in的值@PostConstruct(例如在显式初始化或构造函数中的初始化之后),那么@PostConstruct
将不会首先写入 该属性怎么办?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。