枚举有助于创建单身人士。我知道枚举方法不是线程安全的,所以我试着让它成为线程安全的。任何人都可以确认这种实施是否正确。是否可以使用静态和易失性这么多地方并且可以进行优化?由于内部类是私有的,因此我必须在枚举中创建函数以访问内部类功能。可以优化吗?
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());
答案 0 :(得分:8)
首先,您的枚举中不需要嵌套类。您只需要在枚举本身中定义成员和方法,即
enum Blah {
INSTANCE;
private int someField;
public int getSomeField() { return someField; }
}
现在你可以这样访问你的单例方法:
int someField = Blah.INSTANCE.getSomeField();
此外,使成员静态在这里是一种反模式,因为单例实例应该拥有其成员。所以它们应该是实例变量,而不是静态变量。事实上,只有一个单例实例确保您的JVM中只有一个每个成员的实例。
就线程安全而言,我个人更喜欢原子变量而非易失性,例如,
private final AtomicInteger count = new AtomicInteger();
private final AtomicReference<Date> date = new AtomicReference<>(new Date());
请注意,必须才能声明为final
才能真正保证线程安全,因为原子变量本身不会改变,尽管它们的值可以。
如果您只需要编码的操作,那么volatile变量应该有效。与易失性对应物相比,原子变量提供了更多操作,例如,Java 7为compareAndSet
,Java 8为getAndUpdate
和updateAndGet
。请参阅this进行讨论。
但是,如果您的成员变量是线程安全的和,那么您声明它们(原子/易失性)它们的线程安全策略是独立的,您不需要担心单例中方法的安全性。如果你需要例如一次性原子地更新两个变量,那么你必须重新考虑设计并引入适当的锁(在设置和获取它们的值时)。
非常谨慎地修改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,分别了解有关并发和单例模式的更多信息。