当前位置: 首页 > 知识库问答 >
问题:

在Spring单例Bean中存储状态(添加了线程安全机制)是一种好的做法吗

杜正奇
2023-03-14

来自Spring文档:

7.5.2 (...)通常,对所有有状态bean使用原型作用域,对无状态bean使用单例作用域。

案例:
我有需要存储状态的独立应用程序(例如,一些非常简单的缓存实现为简单的Map)。在我看来,最简单的解决方案是创建具有单例作用域的Sping Bean并将其放在HashMap/ConvoltHashMap中并添加线程安全的get/set方法。

是好的解决方案/实践还是不好?如果不是——正确的方法是什么?

共有3个答案

戎洛华
2023-03-14

从这个答案来看,“有状态”一词似乎是指单一依赖的范围。

也就是说,当我们想要一个不会在注入该bean的其他两个bean之间共享的状态时,这就是为什么要为每个注入使用原型范围-新实例。

因此,要保存应用程序级缓存,默认范围似乎是单例缓存。

我喜欢这种方法,因为它是直接的和可控的,只要记住线程安全问题。

(提示:原子参考是一个“并发包装器”,以防您不需要映射)

封锐藻
2023-03-14

如果您只需要缓存几个键,并且打算使用ConcurrentHashMap来解决并发问题(但如果不考虑此缓存上的性能,您甚至可以使用同步块),那么就可以了。还有更多现成的解决方案,如Spring缓存注释参见Spring缓存或其他内存缓存,如咖啡因,它们不仅处理并发性和其他重要的事情,如值逐出。

但一般来说,缓存很像一个存储库,所以单例作用域是适合这种组件的。

颜云瀚
2023-03-14

是和否。使用自定义构建的Spring组件可能会导致混乱(竞争条件、缓存丢失...)。

那怎么办呢?

为什么不直接使用Spring的CacheManager呢?它可以作为bean手动注入。缓存可以是“设置”或“获取”。您可以使用缓存逐出策略使其完全由注释驱动:

// Cache collection after the first invocation
@Cacheable("people")
public List<Person> getPeople() {...}


// Refresh entries after altering or inserting a new instance of Person
@CacheEvict(value="people", allEntries = true)
public Person save(Person person) {...}

默认的CacheManager实现在后台使用ConcurentHashMap。

 类似资料:
  • 我想知道Spring单例豆是否是线程安全的,如果是,那么为什么,如果不是,那么为什么? 因为我是初学者,所以帮助将不胜感激。

  • 问题内容: 我正在使用Spring Data(JPA)存储库来处理CRUD样板。 我这样定义我的存储库接口: 然后Spring自动为我生成上述接口的实现。我们得到的是代理,但我相信最终我们可以归结为。 如果 基础目标类是线程安全的, 则 A 是线程安全的。因此,问题是:线程安全吗? 问题答案: 通常,是的。假设是一个托管对象,我们将从Spring的工厂类(如果您使用Spring作为容器)或CDI托

  • 问题内容: 有关Singletons的维基百科文章提到了一些用线程安全的方法来用Java实现结构。对于我的问题,让我们考虑具有冗长的初始化过程并且一次被多个线程访问的Singleton。 首先,这个未提及的方法是线程安全的吗?如果是的话,它在什么上进行同步? 其次,为什么以下实现线程安全且在初始化时是懒惰的?如果两个线程同时进入该方法,到底会发生什么? 最后,在第二个示例中,如果一个线程首先获取一

  • 我已经设置了AWS EC2实例,它正在运行。当我尝试从本地框ping时,它不可用。我找到的解决方案似乎都不起作用。我在安全组中添加了一条规则: 我已经完全禁用了Windows防火墙(仅用于测试)。我仍然无法 ping 此实例。

  • 静态编程语言单例(更具体地说,对象声明)在结构上是线程安全的吗?如果不是,用静态编程语言编写线程安全单例的最佳实践是什么? 我想是的,但我在文件中找不到任何明确的声明。

  • 我在多线程环境中做的工作很少。所以,我需要知道below类的getInstance函数是否是线程安全的。这是单例类: 在getInstance函数(未注释)中,返回静态对象的引用。它需要线程安全机制吗? 在第二个getInstance(注释)中,如果singleObject为null,我们就创建对象。所以,它需要锁定机制,需要同步,对吧?