List.copyOf()、Set.copyOf()、Map.copyOf() 的返回值是线程安全的吗?

Gil*_*ili 5 java collections thread-safety

自 2008 年起,Stackoverflow 上就有许多 问题询问不可修改的集合是否是线程安全的,但 JDK 10(2018 年发布)引入了一个不同的野兽:现有集合的不可修改副本

List.copyOf()状态:

如果给定的 Collection 随后被修改,则返回的 List 将不会反映此类修改。

这是否意味着 , , 的返回值List.copyOf()都是Set.copyOf()线程Map.copyOf()安全的?

(我意识到集合中包含的元素本身不能保证是线程安全的。)

Hol*_*ger 6

List.of(\xe2\x80\xa6)由于通过例如或创建的集合List.copyOf(\xe2\x80\xa6)不反映对指定数组或集合的后续更改,并且通常是不可变的,因此在构造之后并且在没有并发修改的情况下不可能执行修改,因此可以\x80\x99 不会有任何线程安全问题。

\n

剩下的问题是这些馆藏的建设本身是否不受不安全出版的影响。通常,您应该使用正确的构造将对象发布到其他线程,而不是依赖于不安全的发布。

\n

但回想一下,不可修改的列表

\n
\n
    \n
  • 它们是不可修改的。无法添加、删除或替换元素。调用 List 上的任何 mutator 方法总是会导致UnsupportedOperationException抛出异常。但是,如果所包含的元素本身是可变的,则可能会导致列表的内容看起来发生变化。
  • \n
\n

\xe2\x80\xa6

\n\n
\n

沿着基于价值的链接,我们发现:

\n
\n

基于价值的课程

\n

某些类(例如java.lang.Integerjava.time.LocalDate)是基于值的。基于值的类具有以下属性:

\n
    \n
  • 该类仅声明最终实例字段(尽管这些字段可能包含对可变对象的引用);
  • \n
\n

\xe2\x80\xa6

\n
\n

Final 字段对于旨在免受不安全发布影响的不可变对象非常重要。如JLS\xc2\xa717.5。final字段语义指定:

\n
\n

final字段还允许程序员无需同步即可实现线程安全的不可变对象。线程安全的不可变对象被所有线程视为不可变,即使使用数据争用在线程之间传递对不可变对象的引用也是如此。这可以提供安全保证,防止错误或恶意代码滥用不可变类。

\n
\n

但我们仍然必须假设意图 \xe2\x80\x9c 在 JDK 开发人员\xe2\x80\x99s 端实现线程安全的不可变对象\xe2\x80\x9d,而不是例如通过显式使用字段来让开发人员感到惊讶的final意图然后故意破坏安全保障。

\n

如有疑问,请使用安全出版物。它不会伤害\xe2\x80\x99。

\n

即使您已经说过这一点,重要的是要强调,如果所包含的元素是可变的,则这不适用于它们。

\n