我可以在集合上使用 volatile 吗?

Jin*_*won 0 java enums volatile lazy-initialization

我有一个枚举,我想我可以缓存values().

enum MyEnum {

    SOME;

    private static volatile Set<MyEnum> values_;

    public static Set<MyEnum> values_() {
        Set<MyEnum> result = values_;
        if (result == null) {
            values_ = result = Collections.unmodifiableSet(EnumSet.allOf(MyEnum.class));
        }
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试了允许重复初始化的延迟初始化。

奏鸣曲也有volatile Set<MyEnum>部分抱怨。

SonaLint:使用线程安全类型;添加“易失性”不足以使该字段成为线程安全的。

https://rules.sonarsource.com/java/RSPEC-3077

我的代码有问题吗?

Bas*_*que 6

Set.of ( MyEnum.values() )

将数组静态地输入Enum#values()到Set.of方法中以创建不可修改的集合似乎要简单得多。

请参阅在 Ideone.com 上实时运行的代码。

enum Animal {
    DOG, CAT, BIRD ;

    public static final Set < Animal > values = Set.of ( Animal.values() ) ;  // A cached set of all enum objects.
}
Run Code Online (Sandbox Code Playgroud)

存在static意味着该代码在类加载时运行。所以线程安全。不需要volatile。

存在final意味着引用变量不能更改为指向另一个集合。分配的原始集将是应用程序运行期间的唯一集。

作为一个不可修改的集合,您可以直接提供对该静态字段的访问,而不是通过方法。

该Set.of方法可以自由返回其选择的具体类的对象。Java 当前或未来的实现可能会选择使用类,例如EnumSet为了提高效率。Ideone.com 使用的 Java 12 实现使用了该类java.util.ImmutableCollections.SetN,但我们并不真正关心。

用法:

Set < Animal > values = Animal.values ; 
Run Code Online (Sandbox Code Playgroud)

[狗、鸟、猫]

你说:

惰性初始化

Set对于从数组中创建 a 这样的微不足道的工作,不需要偷懒、延迟初始化Enum.values()。


但我不推荐这样做。

您缓存此集的意图似乎陷入了过早优化的陷阱。请参阅Brian Goetz的评论。

众所周知,程序员不善于直觉瓶颈。现代 JVM 是有史以来最优化的软件之一。

我建议让客户端程序员调用通常的Enum#values().