当我遇到有关使用volatile
和synchronize
关键字会降低您的整体性能的陈述时,我正在阅读有关volatile的信息,因此下面的代码创建了单例类
public enum Singleton {
INSTANCE
}
最好制作一个单例类,其中包含一个易失性实例和一个同步方法以返回该静态实例。
尽管这两个类都是线程安全的,并且给出相同的期望结果。除了代码的可读性之外,使用枚举还有什么性能上的好处。
答案 0 :(得分:1)
也许volatile
并没有按照您的想象做。您的问题文本似乎是您在询问有关在多线程环境中安全发布单例的两种不同方式。但是,这不是volatile
的目的。 volatile
解决了一个更普遍的问题。
如果需要在不同线程之间共享变量,则可以将其声明为volatile
,但不必与任何其他变量将其声明为synchronized
。 volatile
声明可确保线程每次查看变量时,始终会看到分配给它的最新值,即使该值是由其他线程分配的。
是的。 volatile
很昂贵。在不需要时使用它是错误的(例如,在未共享的变量上使用它是错误的,而在已经存在的共享变量上使用它是错误的)受其他方式保护。)
答案 1 :(得分:0)
synchronized
关键字会降低性能,因为它仅允许一个线程来处理同步代码块。使用synchronized
和volatile
创建单例类的唯一原因是为该类的单个实例提供了延迟初始化。
private static volatile ThreadSafeLazySingleton instance;
private ThreadSafeLazySingleton(){}
public static synchronized ThreadSafeLazySingleton getInstance(){
if(instance == null){
instance = new ThreadSafeLazySingleton();
}
return instance;
}
当实例化占用大量资源并且您希望将实例的创建延迟到最后一刻时,惰性初始化很有用。
使用Reflection
可以打破类的单例设计,而使用Singleton.class.getDeclaredConstructors()
可以将私有构造函数true
设置为对constructor.setAccessible(true)
的访问权限。
使用enum
设计单例类克服了上述缺陷,因为Java确保枚举始终仅被实例化一次。但是,这种方法失去了延迟初始化的好处。由于不使用同步,因此该方法将比同步方法具有更好的性能。
设计单例类的最佳方法是使用此answer
中建议的方法