以下爲單例模式實現的3種常用方式。
(1)餓漢模式
public class Hungry {
private Hungry() { }//單例模式都要注意隱藏構造器
private static Hungry singleTon = new Hungry();
public static Hungry getSingleTon(){
return singleTon;
}
/*測試*/
public static void main(String[] args){
for(int i=0;i<10;i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Hungry.getSingleTon());
}
}).start();
}
}
}
執行結果:
com.bee.sample.ch1.practice.Hungry@64669643
com.bee.sample.ch1.practice.Hungry@64669643
com.bee.sample.ch1.practice.Hungry@64669643
... ...(忽略幾行)
【點評】是線程安全的,但是系統啓動,在類加載時,會直接new出一個對象,導致系統啓動變慢。
(2)懶漢模式
public class SynDoubleCheckLazy {
private SynDoubleCheckLazy(){}
private static SynDoubleCheckLazy singleTon=null;
public static SynDoubleCheckLazy getSingleTon(){
if(singleTon==null){
//這個Thread.sleep僅僅爲測試多線程,製造障礙,使用時刪去
try{
Thread.sleep(200);
}catch (Exception e){
e.printStackTrace();
}
synchronized (SynDoubleCheckLazy.class){
if(singleTon==null){
singleTon=new SynDoubleCheckLazy();
}
}
}
return singleTon;
}
/*以下爲測試*/
public static void main(String[] args){
for(int i=0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(SynDoubleCheckLazy.getSingleTon());
}
}).start();
}
}
}
【點評】線程安全,且效率優良,值得推薦。兩次判斷getSingleTon 返回對象是否爲空,第一次是效率需要,如果非空,直接返回,不用進入下面的同步模塊損失效率,第二次是安全需要。
(3)私有靜態內部類模式
package com.bee.sample.ch1.practice;
public class PrivateStaticInner {
private PrivateStaticInner(){}
private static class PrivateStaticInnerHolder{
private static PrivateStaticInner singleTon = new PrivateStaticInner();
}
public static PrivateStaticInner getSingleTon(){
return PrivateStaticInnerHolder.singleTon;
}
/*測試*/
public static void main(String[] args){
for(int i=0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(PrivateStaticInner.getSingleTon());
}
}).start();
}
}
}
【點評】線程安全,外貌和餓漢模式相似,兩者都是利用類加載的方式來實現初始化時只有一個線程,區別在於PrivateStaticInner 加載時,不會立刻實例化,而是調用getSingelTon方法時,纔會裝載內部類PrivateStaticInnerHolder,從而完成父類PrivateStaticInner 的實例化,值得推薦。