单例模式_你懂了么

-确保一个类在任何情况下都绝对只有一个实例,并提供一个全局的访问点-

-隐藏其所有的构造方法

-属于创建型模式

(例如:servletContext、ServletConfig、ApplicationContext)

 

单例模式常见写法:

1 饿汉式单例

在单例内首次加载就创建实例

public class HungrySingleton{

private static final HungrySingleton hungrySingleton = new HungrySingleton();

 

private HungrySingleton(){

}

 

public static HungrySingleton getInstance(){

    return hungrySingleton;

   }

}

 

缺点:浪费内存空间(不管使不使用、都会创建实例)

2 懒汉式单例

public class LazySingleton{

 

// volatile 解决重排序问题

private volatile static LazySingleton lazySingleton= null;

private LazySingleton(){

}

 

// 多线程情况下,不能保证单例,或者存在覆盖

1.public static LazySingleton getInstance(){

      if(lazySingleton == null){

      lazySingleton = new LazySingleton ()

      }

     return lazySingleton;

}

 

// 可能存在性能问题

2.public synchronized static LazySingleton getInstance(){

      if(lazySingleton == null){

       lazySingleton = new LazySingleton ()

       }

      return lazySingleton;

}

 

// 双重判断加锁

3.public static LazySingleton getInstance(){

   if(lazySingleton == null){

      synchronized (LazySingleton.class){、

         if(lazySingleton == null){

            lazySingleton = new LazySingleton ();

             //cpu执行的时候会转换成JVM指令

            // 指令重排序的问题,volatile

            // 1、分配内存给对象

           // 2、初始化对象

           // 3、将初始化好的对象和内存地址建立关联,赋值

          // 4、用户初次访问

          }

      }

  }

  return lazySingleton;

  }

}

 

4.静态内部类方式实现(性能最优实现)

public class LazyInnerClassSingleton{

 

  // 可通过反射获取实例,则有可能存在多个实例

  private LazyInnerClassSingleton(){

  // 解决反射-如果想通过反射,则直接抛出异常

    if( LazyHolder.lazy ! = null){

      throw new RuntimeException("不允许构建多个实例");

    }

  }

 

  public static final LazyInnerClassSingleton getInstance(){\

    return LazyHolder.lazy ;

  }

 // 内部类的内容需要在外部调用时才会执行

 private static class LazyHolder{

  private static final LazyInnerClassSingleton lazy = new LazyInnerClassSingleton();

  }

}

 

--仍然有可能通过序列破坏单例

 

// 解决,源码hasReadResolve方法会判断,有则直接由单例代替新创建的对象

// 重写readResolve 。还是创建了两次对象,新创建对象会被GC

private Object readResolve(){

  return 单例对象

}

 

3 注册式单例

1.枚举式单例 jdk层面保证了单例

public enum EnumSingleton{

   INSTANCE;

 

   private Object data;

 

   // 省略get set

 

  public static EnumSingleton getInstance(){

     return INSTANCE;

  }

}

2.容器式单例(例如springioc 方便管理单例对象)

// 存在线程安全问题 可通加锁解决

public class ContainerSingleton{

  private ContainerSingleton(){}

  private static Map<String,Object> ioc = new ConcurrentHashMap<>();

 

  public static Object getBean (String className){

    synchronized(ioc){

      if(! ioc.containsKey(className)){

        obj = Class.forName(className).newInstance();

        ioc.put(className,obj);

      }

      return ioc.get(className);

    }

 

  }

}

4 ThreadLocal单例

// 伪线程安全 同一个线程内单例。不同线程则是不同实例

// 如orm实现多数据源动态切换

public class TheadLocalSingleton{

 

  public TheadLocalSingleton(){}

 

  private static final ThreadLocal<TheadLocalSingleton> threadLocalInstance =

    new ThreadLocal<TheadLocalSingleton>(){

    protected TheadLocalSingleton initialValue(){

        return new TheadLocalSingleton();

    }

  }

 

  public static TheadLocalSingleton getInstance(){

    return threadLocalInstance.get();

  }

}

 

 

-- 单例缺点:扩展性不强,扩展需要更改代码。

设计单例模式需要思考的:

1,私有化构造器

2.保证线程安全

3.延迟加载

4.防止序列化和反序列化破坏单例

5.防御反射攻击单例

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叁达补溜

求个三连

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值