单例模式 Singleton

坚强是说给别人听的谎言 提交于 2020-02-11 12:27:47

单例模式

简介

单例模式保证内存中对象只存在一个实例
单例模式分为饿汉式懒汉式

饿汉式

  • 特点
    • 当类被加载到内存时,就会实例化对象,保证JVM线程安全
    • 缺点:不管使不使用,类加载时就会实例化

懒汉式

  • 特点
    • 按需加载,类尽管被加载到内存中,但不会立刻被实例化
    • 第一次使用时会实例化,以后便存在内存中
    • 缺点:多线程访问时,可能会创建多个实例

8种单例模式

第一种 饿汉式

/**
 * 单例模式:保证内存中只有一个实例
 * 饿汉式
 * 类加载到内存后,就实例化一个单例,JVM保证线程安全
 * 简单使用,推荐使用
 * 唯一缺点:不管使不使用,类加载时就完成实例化
 */
public class Mgr1 {
   private static final Mgr1 INSTANCE = new Mgr1();

   /**
    * 阻止外部创建实例对象
    */
   private Mgr1(){}

   public static Mgr1 getInstance(){
      return INSTANCE;
   }
}

第二种 饿汉式:在静态块中实例化对象

/**
 * 单例模式:保证内存中只有一个实例
 */
public class Mgr2 {
   private static final Mgr2 INSTANCE;

   static {
      INSTANCE = new Mgr2();
   }

   /**
    * 阻止外部创建实例对象
    */
   private Mgr2(){}

   public static Mgr2 getInstance(){
      return INSTANCE;
   }
}

第三种 懒汉式

/**
 * 懒汉式lazy loading
 * 按需实例化(第一次使用时才实例化),却带来了线程不安全问题(多个实例)
 */
public class Mgr3 {
   private static Mgr3 INSTANCE;

   /**
    * 阻止外部创建实例对象
    */
   private Mgr3(){}

   public static Mgr3 getInstance(){
      if(INSTANCE == null){
         INSTANCE = new Mgr3();
      }
      return INSTANCE;
   }
}

第四种 懒汉式:在方法上加锁,保证线程安全,但降低了效率

/**
 * 懒汉式lazy loading
 * 按需实例化(第一次使用时才实例化),却带来了线程不安全问题(多个实例)
 * 加锁解决线程安全问题,但是会降低效率
 */
public class Mgr4 {
   private static Mgr4 INSTANCE;

   /**
    * 阻止外部创建实例对象
    */
   private Mgr4(){}

   public static synchronized Mgr4 getInstance(){
      if(INSTANCE == null){
         INSTANCE = new Mgr4();
      }
      return INSTANCE;
   }
}

第五种 懒汉式:

/**
 * 懒汉式lazy loading
 * 按需实例化(第一次使用时才实例化),却带来了线程不安全问题(多个实例)
 * 加锁解决线程安全问题,但是会降低效率
 */
public class Mgr5 {
   private static Mgr5 INSTANCE;

   /**
    * 阻止外部创建实例对象
    */
   private Mgr5(){}

   public static Mgr5 getInstance(){
      if(INSTANCE == null){
         //该方式不能解决线程安全问题
         synchronized(Mgr5.class){
            INSTANCE = new Mgr5();
         }
      }
      return INSTANCE;
   }
}

第六种 懒汉式:双重检查

/**
 * 懒汉式lazy loading
 * 按需实例化(第一次使用时才实例化),却带来了线程不安全问题(多个实例)
 * 加锁解决线程安全问题,但是会降低效率
 * 双重检查会提高效率
 */
public class Mgr6 {
   private static volatile Mgr6 INSTANCE;//volatile 防止JVM指令重排

   /**
    * 阻止外部创建实例对象
    */
   private Mgr6(){}

   public static Mgr6 getInstance(){
      if(INSTANCE == null){
         //双重检查
         synchronized(Mgr6.class){
            if(INSTANCE == null){
               INSTANCE = new Mgr6();
            }
         }
      }
      return INSTANCE;
   }
}

第七种 饿汉式改良版:使用静态内部类持有单例对象,实现懒加载

/**
 * 单例模式:保证内存中只有一个实例
 * 静态内部类方式
 * 加载外部类时,不会加载静态内部类,实现懒加载
 */
public class Mgr7 {

   /**
    * 静态内部类在外部类加载时不会被加载
    */
   private static class Mgr7Holder{
      private static final Mgr7 INSTANCE = new Mgr7();
   }

   /**
    * 阻止外部创建实例对象
    */
   private Mgr7(){}

   public static Mgr7 getInstance(){
      return Mgr7Holder.INSTANCE;
   }
}

第八种 枚举单例:防止反序列化

/**
 * 枚举单例,防止反序列化
 */
public enum Mgr8 {
   INSTANCE;

   //其他方法
   public void m(){}
}

在实际生产过程中,使用最多的还是第一种饿汉式单例模式,饿汉式通过静态内部类的方式实现懒加载的方式也是可以的,因为懒汉式涉及到了同步锁机制,降低了执行效率,所以不建议使用,在实际生产环境中,大家应该按情况选择不同的单例模式

奥里给!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!