java中单例模式介绍与反思

众所周知,在java中单例模式实现有7种,分别如下:

1、懒汉模式(线程不安全)

        public class Singleton{

                   private static Singleton instance;

                   private Singleton(){};

                   public static Singleton getInstance(){

                              if(instance == null ){

                                     instance = new Singleton();

                               }

                        return instance;

                    }

         }

这种模式采用懒加载lazy loading但是在多线程下不安全

2、懒汉模式(线程安全)

 public class Singleton{

                   private static Singleton instance;

                   private Singleton(){};

                   public static synchronized Singleton getInstance(){

                              if(instance == null ){

                                     instance = new Singleton();

                               }

                        return instance;

                    }

         }

懒加载,线程安全,但效率极其低下,同步锁锁的是对象,每次取对象都加锁,因此效率低下

3、饿汉模式

public class Singleton{

                   private static Singleton instance= new Singleton();

                   private Singleton(){};

                   public static Singleton getInstance(){

                       return instance;

                    }

         }

这种方式基于classloader机制避免了多线程同步问题,不过instance在类装载时就实例化,没有达到懒加载效果

4、饿汉模式变种

public class Singleton{

                   private static Singleton instance = null;

                   static{

                        instance= new Singleton();

                   }

                   private Singleton(){};

                   public static Singleton getInstance(){

                       return instance;

                    }

         }

等同于第三种

5、静态内部类

public class Singleton{

                   private Singleton(){};

                   public static synchronized Singleton getInstance(){

                       return SingletonInnerClass.instance;

                    }

                  private static class SingletonInnerClass(){

                       private static Singleton instance = new Singleton();

                  }

         }

 利用classloader机制保证初始化实例时只有一个实例,与第三种第四种差别是达到了懒加载效果(第三种第四种方法只要singleton类被装载了那么instance就会被实例化,而这种方式SingletonInnerClass类没有被主动使用,只有被显示调用getInstance时才会显示装载SingletonInnerClass类,从而实现懒加载)在实例化instance很消耗资源,想让他延迟加载,另外不希望在singleton类加载时就实例化,这种方式就显得很合理 。推荐使用

6、双重校验锁

public class Singleton{

                   private static Singleton instance;

                   private Singleton(){};

                   public static synchronized Singleton getInstance(){

                      if(instance == null){

                              synchronized(Singleton.class){

                                     if(instance == null){

                                           instance = new Singleton();

                                      }

                                }

                      }

                       return instance;

                    }

         }

不管性能如何优越,使用了synchronized修饰符,就会对性能多少造成影响

7、枚举

    public enum SIngleton{

             INSTANCE;

             public void whateverMethod(){}

}

这种方式是Effective Java提倡方式,不仅能避免多线程同步问题,还能防止反序列化重新创建新的对象,但因为可读性原因不推荐

由此七方法也介绍完毕,但也有几个问题需要反思

1、如何在反射状态下保证单例?

2、如何在反序列化中保证单例?

对于第一个问题我们可以采取以下方式

public class Singleton3{

             private static boolean initialized = false;

             private Singleton3(){

                    synchronized(Singleton3.class){

                             if(initialized == false){

                                  initialized = !initialized ;

                             }else{

                                  throw new RuntimeException("单例已破坏");

                             }

                       }

                 }

             static class SingletonHolder{

                   private static final Singleton3 instance = new Singleton3();

              }

             public static Singleton3 getInstance(){

                           return SingletonHolder.instance;

             }

}

这就保证了反射无法破坏其单例

对于第二个问题我们需要提供readResolve()方法的实现,来代替从流中读取对象,这就确保了序列化和反序列化过程中没人可以创建新的实例

public class Singleton4 implements Serializable{

             private static boolean initialized = false;

             private Singleton4(){

                    synchronized(Singleton4.class){

                             if(initialized == false){

                                  initialized = !initialized ;

                             }else{

                                  throw new RuntimeException("单例已破坏");

                             }

                       }

                 }

             static class SingletonHolder{

                   private static final Singleton4 instance = new Singleton4();

              }

             public static Singleton4 getInstance(){

                           return SingletonHolder.instance;

             }

            private Object readResolve(){

                   return getInstance();

             }

}

本文给出了多种单例模式,一般从静态内部类和保证反射,序列化状态下单例选择,根据实际情况三选一即可,并不是非要选择最后一种作为单例实现

   


    

                              


你可能感兴趣的:(设计模式)