关于Singleton的实现方式,有如下多种方式,究竟那一种是高效安全的呢?
1、大家熟知的懒式单例
public class LazySingleton {
private static LazySingleton instance = null;
private static boolean flag = true;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
letMeSleep() ;
instance = new LazySingleton();
}
System.out.println("instance.hashCode() : " + instance.hashCode());
return instance;
}
private static void letMeSleep() {
if (true) {
try {
System.out.println("let me sleep 3 sec.!");
Thread.currentThread().sleep(3000);
System.out.println("waking up.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] agrs) {
//实例化两个线程
new Thread(new Runnable() {
public void run() {
LazySingleton s = LazySingleton.getInstance();
}
}).start();
new Thread(new Runnable() {
public void run() {
LazySingleton s = LazySingleton.getInstance();
}
}).start();
}
}
执行结果分析:
let me sleep 3 sec.!
let me sleep 3 sec.!
waking up.
instance.hashCode() : 6413875
waking up.
instance.hashCode() : 21174459
每个线程获取的实例不一样。
2、好吧,用同步synchronized
有人是这样实现的:
public static LazySingleton getInstance() {
if (null == instance) {
synchronized (LazySingleton .class) {
instance = new LazySingleton ();
}
}
return instance;
}
这样是否正确呢,我们还用上面的思路来进行测试:
let me sleep 3 sec.!
let me sleep 3 sec.!
waking up.
instance.hashCode() : 21174459
waking up.
instance.hashCode() : 827574
结果很不幸:(。原因在于在两个线程都执行到了if (null == instance) 里面的逻辑,然后依次执行 instance = new LazySingleton (); 这样获取两个instance实例就是正常的了。到了这里,大家都肯定知道在执行 instance = new LazySingleton () 还要判断下instance是否为空。同步块影响性能吧?想必答案是肯定的。
3、简单,安全的写法:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
letMeSleep() ;
System.out.println("instance.hashCode() : " + instance.hashCode());
return instance;
}
这样的写法简单,也安全。但是考虑到构造函数里面加载很多东西,势必延长初始化时间。
4、利用静态内部类提前实例化
public class HolderSingleton {
private HolderSingleton(){
}
public static class SingletonHolder{
private static HolderSingleton instance = new HolderSingleton() ;
}
public static HolderSingleton getInstance(){
letMeSleep();
System.out.println(SingletonHolder.instance.getClass().hashCode()) ;
return SingletonHolder.instance ;
}
private static void letMeSleep() {
if (true) {
try {
System.out.println("let me sleep 3 sec.!");
Thread.currentThread().sleep(3000);
System.out.println("waking up.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这个在JVM这一个层次有第三中山实现方式有何不一样?