问题
I want to implement Thread Safe Lazily Loaded Singleton in Java.
Is this a good design?
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;
}
}
}
I also want to create a lock-less version for use in a scenario where one thread accesses the Singleton many more times than the other threads, how would I achieve this using the atomic objects in Java, ie AtomicBoolean or AtomicReference etc. Could you provide a code example please?
回答1:
A better design would be
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;
}
}
}
However, the best design IMHO is
public enum ThreadSafeLazySynchronizedSingleton {
INSTANCE;
}
回答2:
The recommended approach to implementing Singleton design pattern in Java is using the Enum approach. The Enum approach is very simple and thread safe implicitly.
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();
}
}
Nice tutorial here.
回答3:
The simplest thing will probably be as lazy as you need it:
private static ThreadSafeLazySynchronizedSingleton instance
= new ThreadSafeLazySynchronizedSingleton();
public static ThreadSafeLazySynchronizedSingleton instance() {
return instance;
}
True, instance
will be created as soon as the class is loaded. But the class won't be loaded until it's used, and at that point you probably need to get the instance, anyway.
The only time this wouldn't be as lazy as you need is if the ThreadSafeLazySynchronizedSingleton
class also had static helper methods that don't use instance
, but that would suggest they don't have much to do with the rest of the class and should probably be moved to their own class.
A lot of people also use a single-value enum
for singletons. Personally I find it ugly, but it does have some advantages (handles the private constructor and instance
for you, and the singleton-ness is enforced even if your class is serializable, which is otherwise not trivial).
回答4:
If you wanted a true lock-free implementation it would require some spinning. Otherwise @yshavit or @Peter Lawrey are the best possible answers.
Lock Free:
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;
}
来源:https://stackoverflow.com/questions/24434566/is-this-a-good-implementation-for-a-thread-safe-lazily-loaded-singleton-in-java