线程安全的Enum Singleton

枚举有助于创建单身人士。 我知道枚举方法不是线程安全的,所以我试着让它成为线程安全的。 任何人都可以确认这种实施是否正确。 是否可以使用静态和易失性这么多地方并且可以进行优化? 由于内部类是私有的,因此我必须在枚举中创建函数以访问内部类function。 可以优化吗?

import java.util.Date; public enum SingletonWithEnum { INSTANCE; private static class Singleton{ private static volatile int count; private static volatile Date date; public static int getCount() { return count;} public static void setCount(int countParam) { synchronized(Singleton.class){ count = countParam; }} public static Date getDate() { return date;} public static void setDate(Date dateParam) { synchronized(Singleton.class){ date = dateParam;}} public static String printObject() { return "Singleton [count=" + getCount() + ", date=" + getDate() + "]"; } } public int getCount() { return Singleton.getCount();} public void setCount(int countParam) {Singleton.setCount(countParam);} public Date getDate() { return Singleton.getDate();} public void setDate(Date dateParam) {Singleton.setDate(dateParam);} public String toString(){return Singleton.printObject();} }; 

我这样用它。

 SingletonWithEnum object1 = SingletonWithEnum.INSTANCE; object1.setCount(5); object1.setDate(new Date()); 

首先,你的枚举中不需要嵌套类。 你只需要在枚举本身中定义成员和方法,即

 enum Blah { INSTANCE; private int someField; public int getSomeField() { return someField; } } 

现在,您可以通过以下方式访问单例方法:

 int someField = Blah.INSTANCE.getSomeField(); 

此外,使成员静态在这里是一种反模式,因为单例实例应该拥有其成员。 所以它们应该是实例变量,而不是静态变量。 事实上,只有一个单例实例可确保您的JVM中只有一个每个成员的实例。

就线程安全而言,我个人更喜欢primefaces变量而不是volatile,例如:

 private final AtomicInteger count = new AtomicInteger(); private final AtomicReference date = new AtomicReference<>(new Date()); 

请注意,它们必须被声明为final才能真正保证线程安全,因为primefaces变量本身不会改变,尽管它们的值可以。

如果您只需要编码的操作,那么volatile变量应该可以工作。 与其易失性对应物相比,primefaces变量提供了更多操作,例如,针对Java 7的compareAndSet和针对Java 8的getAndUpdateupdateAndGet 。请参阅此讨论。

但是,如果您的成员变量是线程安全的并且它们的线程安全策略是独立的,那么您声明它们(primefaces/易失性),您不需要担心单例中方法的安全性。 如果你需要例如一次性primefaces地更新两个变量,那么你将不得不重新考虑设计并引入适当的锁(在设置获取它们的值时)。

非常谨慎地修改Date对象的方式非常重要。 Date 不是线程安全的,所以我强烈建议在进行更改时返回副本并用副本替换实例,即(假设您使用的是AtomicReference ),

 public Date getDate() { return new Date(date.get().getTime()); } public void setDate(Date d) { date.set(new Date(d.getTime())); } 

最后,我强烈推荐Brian Goetz的Concurrency in Practice和Joshua Bloch的Effective Java,分别了解有关并发和单例模式的更多信息。