我想在Java中实现线程安全的惰性加载单例。
这个设计好吗?
public final class ThreadSafeLazySynchronizedSingleton {
private ThreadSafeLazySynchronizedSingleton(){}
private static ThreadSafeLazySynchronizedSingleton instance;
public static ThreadSafeLazySynchronizedSingleton getSynchronizedInstance(){
synchronized(ThreadSafeLazySynchronizedSingleton.class){
if (instance==null){
instance = new ThreadSafeLazySynchronizedSingleton();
}
return instance;
}
}
}
我还想创建一个无锁版本,用于在一个线程访问Singleton的次数多于其他线程的情况下,我如何使用Java中的原子对象,即AtomicBoolean或AtomicReference等来实现这一点。你能提供一个代码示例吗?
一个更好的设计是
public final class ThreadSafeLazySynchronizedSingleton {
private ThreadSafeLazySynchronizedSingleton(){}
private static volatile ThreadSafeLazySynchronizedSingleton instance;
public static ThreadSafeLazySynchronizedSingleton getSynchronizedInstance(){
if (instance==null)
synchronized(ThreadSafeLazySynchronizedSingleton.class){
if (instance==null){
instance = new ThreadSafeLazySynchronizedSingleton();
}
return instance;
}
}
}
然而,我认为最好的设计是
public enum ThreadSafeLazySynchronizedSingleton {
INSTANCE;
}
在Java中实现单例设计模式的推荐方法是使用Enum方法。枚举方法非常简单,并且是隐式线程安全的。
public enum EnumTest {
INSTANCE;
// Test code
public static void main(String[] args) {
// First thread
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
EnumTest obj = EnumTest.INSTANCE;
}
});
t1.start();
// Second thread
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
EnumTest obj = EnumTest.INSTANCE;
}
});
t2.start();
}
}
最简单的东西可能会像你需要的那样懒惰:
private static ThreadSafeLazySynchronizedSingleton instance
= new ThreadSafeLazySynchronizedSingleton();
public static ThreadSafeLazySynchronizedSingleton instance() {
return instance;
}
True, instance
将在类加载后立即创建。但是类在被使用之前是不会被加载的,这时你可能需要获取实例。
如果ThreadSafeLazySynchronizedSingleton
类也有不使用instance
的静态助手方法,那么这不会像您需要的那样懒惰,但这表明它们与类的其余部分没有太多关系,可能应该移动到自己的类中。
很多人也将单值enum
用于单例。我个人觉得它很丑,但它确实有一些优点(为您处理私有构造函数和instance
,并且即使您的类是可序列化的,也强制执行单例性,否则这不是微不足道的)。
如果你想要一个真正的无锁实现,它将需要一些旋转。否则,@yshavit或@Peter Lawrey是最好的答案。
锁免费的:
private static final AtomicBoolean created = new AtomicBoolean(false);
private static volatile LazySingleton instance = null;
public static ThreadSafeLazySynchronizedSingleton getIntsance(){
if(instance != null) return instance.get();
if(created.compareAndSet(false, true)){
//only one thread can try and create
instance = new LazySingleton();
} else {
//other thread is creating, spin until ready
while(instance == null);
}
return instance;
}