【问题标题】:Spring bean field thread safetySpring bean 字段线程安全
【发布时间】:2021-01-19 03:01:25
【问题描述】:

我创建了一个 spring 库,其中有一个调度程序,它从 config-server 获取配置并将其注入到 bean 的字段中。 参考下图:

问题是,在重负载下,可能会出现线程并发问题。我应该如何预防?

一些代码:

这是用户提供配置密钥的方式

    @AutoConfig("user")
data class ConfigurationWithPrefix (

    @ConfigValue("role")
    val role: String = ""
)

@AutoConfig
data class ConfigurationWithoutPrefix (

    @ConfigValue("user.role")
    val role: String = ""
)

@AutoConfig 注释将使此类成为一个 bean。 然后我通过 @AutoConfig 注释获取 bean 并将值插入到 @ConfigValue 键中。


field.set(
          bean,
          valueFromConfig
 )

这个过程发生在另一个线程上,所以在插入字段值时如果我的代码试图访问字段并发问题会出现,如何防止它?

【问题讨论】:

  • 关键问题是对象创建后是否被修改。如果不是,那么通常 Spring 会在构造和使用之间提供发生之前的关系。如果对象在创建后被修改,则需要处理某种形式的同步(例如 volatile)。但我会三思而后行。
  • Object 由 Spring 创建并由调度程序稍后修改,除了 Volatile 之外还有其他选项吗?
  • Volatile 本身就是一个很好的解决方案。我不明白你为什么要阻止它。

标签: java spring kotlin concurrency spring-bean


【解决方案1】:

这类似于多线程的缓存读/写,对于这种问题,AtomicReference 效果更好,其语义类似于 volatile 没有同步。

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html

Bean 定义可以转换为:

data class ConfigurationWithPrefix (

    @ConfigValue("role")
    val role: AtomicReference<String> = AtomicReference("")
)

@AutoConfig
data class ConfigurationWithoutPrefix (

    @ConfigValue("user.role")
    val role: AtomicReference<String> = AtomicReference("")
)

【讨论】:

  • AtomicReference 与 get/set 具有与 volatile 相同的语义。
  • 不确定(即使可行)对用户添加如此巨大的限制是否是个好主意。
  • 是的,这是一个有效的观点。我们可以创建一些扩展函数来获取值以轻松访问它。您可以尝试使用带有可重入锁的生产者 - 消费者模式,前提是 Bean 应该是单例的,以便所有线程通过读写锁进行通信。
猜你喜欢
  • 1970-01-01
  • 2013-02-06
  • 2012-07-06
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多