怎样实现Singleton模式才是高效和安全的?
关于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这一个层次有第三中山实现方式有何不一样?