以下为单例模式实现的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 的实例化,值得推荐。