【问题标题】:Should a @Singleton bean return an internal List<> member?@Singleton bean 是否应该返回内部 List<> 成员?
【发布时间】:2015-08-27 07:57:18
【问题描述】:

这可能是一个非常简单的问题,但我并不完全清楚。

我有一个豆子如下:

@Singleton
@Startup
@Lock(READ)
public class SomeDataBean {
  List<Foo> foos;

  @PostConstruct
  public void init() {
    // Build foos;
  }

  public List<Foo> getFoos() {
    return foos;
  }

  @Lock(WRITE)
  public void modifyFoos() {
    // This could be potentially called too
  }
}

随后,这个 bean 被注入(使用 CDI - 环境是 Wildfly 8.2),注入到各种其他 bean(请求/会话/视图等)中。现在他们都访问了这个 Foos 列表。我的问题是,当另一个 bean 可能调用 modifyFoos() 时,按原样返回列表是否安全。或者这是永远不会发生并且由容器保证的事情?

我已经阅读了有关容器管理事务等的一些文档,但尚不完全清楚它在这种情况下是如何工作的。例如,用并发容器替换列表是否更好?

【问题讨论】:

  • 如果您不希望您的列表数据被其他类更改,您应该返回一个副本而不是原始列表的引用。
  • @sgplait,大多数情况下我返回Stream&lt;&gt;() - 我在示例中使用List&lt;&gt;,因为它更通用......但同样的问题适用......(AFAIK,流- 除非由并发容器支持,否则不是线程安全的。!?!)

标签: java java-ee-6


【解决方案1】:

不,这不安全,因为一个线程可以读取列表,而另一个线程修改它。

  1. 返回列表的副本(如果有很多读取,则效率不高)。
  2. 使用copy-on-write 列表。
  3. 将列表的新实例存储在modifyFoos 中。

【讨论】:

  • 要么返回列表的副本(防御性副本),要么如果它是线程安全的,那么您就没有问题(迭代时也要小心,除非它是 CopyOnWriteArrayList)。
  • 我希望得到一些容器魔法酱,嗯,我会坚持退回副本..
  • 您能否更具体地了解“容器魔法酱”?你也应该在那里使用一些同步。
  • 当您使用单例之外的列表时,容器魔法无法帮助您。如果与读取相比写入很少(通常是这种情况),您可以考虑选项 3。
  • 对列表(或其他容器)的结构更改确实很少见,个别 Foos 已正确同步 - 问题更多的是返回是否 安全原始清单 - 对我而言,对内容的不切实际的期望......
猜你喜欢
  • 1970-01-01
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 2017-10-20
相关资源
最近更新 更多