单例模式我们在开发中经常用到,但是我们可能熟知一种单例模式,但是单例模式也有好多种,现在就对几种单例模式做个比较,明白其中的优缺点:

  1. 单例代码:“饿汉式”,也就是当类加载进来的时候就创建实例,但是这种方式比较消耗资源。(单例模式的第一个版本)
public class Singleton{
     private static Singleton single=new Singleton();

     private Singleton(){
          System.out.println("生成一个Singleton实例");
     }

     public static Singleton getInstance(){
          return single;
     }

}

2.测试代码

public class SingletonTest{

     public static void main(String[] args){
         System.out.println("Start...");
         Singleton single1=Singleton.getInstance();
         Singleton single2=Singleton.getInstance();
         if(single1==single2){
             System.out.println("obj1 和 obj2 是相同的实例。"); 
         }else{
             System.out.println("obj1 和 obj2 是不同的实例。");
         }
         System.out.println("End...");

     }
}

3.测试结果

Start...
生成一个Singleton实例
obj1 和 obj2 是相同的实例。
End...

  1. 不是严格的Singleton模式的例子:“懒汉式”:单线程下可以,多线程下存在线程安全问题。(单例模式的第二个版本), 这段代码如果是在单线程中是没有什么问题的,但是因为没有锁的机制,在多线程中就会有问题,当同一时间有两个或者两个以上线程进入getInstance()方法时,因为刚开始single都是null , 几个线程都同时满足if(single==null) 这个条件,就会同时new Singleton() 这个对象
public class Singleton{
     private static Singleton single=null;
     private Singleton(){
         System.out.println("生成一个Singleton实例"); 
     }
     public static Singleton getInstance(){
          if(single==null){
              single=new Singleton(); 
          }
          return single;
     }
}

5.不是严格单例模式测试代码

public class SingletonThread implements Runnable {
     private Set<Singleton> set=new HashSet<Singleton>();
     @Override
     public void run() {
          Singleton single=Singleton.getInstance();
          set.add(single);
          System.out.println("Set的大小为:"+set.size()+","+set);
     }
}

测试类Main方法

public class SingleTest {
     public static void main(String[] args) {
          SingletonThread t=new SingletonThread();
          new Thread(t).start();
          new Thread(t).start();
          new Thread(t).start();
          new Thread(t).start();
          new Thread(t).start();
     }
}

6.测试结果:会看到会有多个“生成一个Singleton实例”,说明调用了5次 new Singleton()方法。
我理解的单例设计模式

7.如果使用第一种方法的话:只会有一个“生成一个Singleton实例 ”,说明只调用了一次 new Singleton() 方法。

我理解的单例设计模式

8.为了解决第二种多线程安全问题,采用对函数进行同步的方式,但是也比较浪费资源,因为每次都要进行同步检查,而实际真正需要检查的只是第一次。(单例模式的第三个版本)

public class Singleton{
     private static Singleton single=null;
     private Singleton(){
         System.out.println("生成一个Singleton实例");
     }
     public static synchronized Singleton getInstance(){
          if(single==null){
              single=new Singleton();
          }
          return single;
     }
}

运行结果:
我理解的单例设计模式

9.(单例模式的第四个版本)既解决了“懒汉式”多线程的安全问题,又解决了浪费资源的现象。

public class Singleton{
     private static Singleton single;
     private Singleton(){
        System.out.println("生成一个Singleton实例");
     }
     public static Singleton getInstance(){
        if(single==null){
          synchronized(Singleton.class) {
              if(single==null) {
              single=new Singleton();
              }
          }
        }
        return single;
   }
}

运行结果:

我理解的单例设计模式

10.单例模式优缺点总结:

优点:客户端使用单例模式的实例的时候,只需要调用一个单一的方法就可以得到一个唯一的实例,有利于节省资源。
缺点:首先单例模式很难实现实例化,这就导致采用单例模式的类很难被持久化,当然也很难通过网络进行传输;其次,由于单例采用静态方法,无法再继承结构中使用。