美文网首页
单例(饿汉、懒汉、静态内部类、枚举)

单例(饿汉、懒汉、静态内部类、枚举)

作者: 日落西风碎 | 来源:发表于2020-03-25 18:20 被阅读0次

    什么是单例

      所谓单例,指的就是单实例,有且仅有一个类实例。

    应用场景

      常应用于不能存在多个实例的场景中。例:计算器等。

    单例的多种写法

      单例存在多种写法:饿汉式、懒汉式、加锁、静态内部类、枚举等。

    饿汉式

      饿汉式,顾名思义就是在类加载时就是创建类的单例,占用资源,线程安全(反射可破)。
      ★ 适用场景:占用资源少的类

    public class HungarySingleton{
        private void HungarySingleton(){}
        private static HungarySingleton hs = new HungarySingleton();
        public static HungarySingleton getInstance(){
                return hs;
        }
    }
    

    懒汉式

       懒汉式是延迟加载,在首次实际调用实例时进行加载,线程不安全。
       ★ 适用场景:单线程

    public class LasySingleton{
          private void LasySingleton(){}
          private static LasySingleton ls ;
          pulbic static getInstance(){
                if(null == ls) ls = new LasySingleton();
                return ls;
          }
    }
    

    单锁式

       单锁式,使用synchronized来同步实例,但这种加锁方式在每一次执行时都要进行同步和判断,影响执行速度。非绝对线程安全(反射、序列化可破)
       ★ 适用场景:

    public class SyncSingleton{
            private void SyncSingleton(){}
            private static SyncSingleton ss;
            public static synchronized SyncSingleton getInstance(){
                    if(null == ss) ss = new SyncSingleton();
                    return ss;
            }
    }
    

    双重判断锁

       双重锁可以解决单锁式,每次访问的加锁问题
       ★ 适用场景:

    public class DoubleSyncSingleton{
            private DoubleSyncSingleton(){};
            private static DoubleSyncSingleton dss;
            public static DoubleSyncSingleton getInstance(){
                  if(null == dss){
                      synchronized (DoubleSyncSingleton.class){
                            if(null == dss) dss = new DoubleSyncSingleton();
                      }
                  }
                  return dss;
            }
    }
    

    静态内部类

       非绝对线程安全(反射可破)。
       JVM在加载类的静态成员只能加载一次,这样JVM层就保证了只会有一个实例对象
       延迟加载:当JVM加载一个类时,其内部不会被同时加载,当且仅当静态成员被调用时发生调用。
       ★ 适用场景:

          public class StaticClassSingleton{
                 private StaticClassSingleton(){}
                 private class Singleton{
                    private static StaticClassSingleton scs = new StaticClassSingleton();
                 }
                public static StaticClassSingleton getInstance(){
                    return Singleton.scs;
                }
    
          }
    

    枚举

       线程绝对安全(反射不可破)、浪费空间
       ★ 适用场景:

    public class EnumSingleton{
          INSTANCE;//单例的实例对象
          private String str;
          public void config(String str){
            str = str;
          }
          public String doSomething(){   
              return str;
          }
    }
    

    反射验单例

      以单锁单例为例

    public class Reflex{
        public void static main(String[] argc){
          System.out.println("破解前: "+(SyncSingleton.getInstance() == SyncSingleton.getInstance() ? "是同一对象" : "不是同一对象"));
          try{
                  // 加载单例
               Class<SyncSingleton> syncSingletonClass = (Class<SyncSingleton>) Class.forName("com.example.SyncSingleton");
                 // 通过反射获取无参构造器
               Constructor<SyncSingleton> constructor = syncSingletonClass.getDeclaredConstructor();
                // 通过无参构造器来生成实例
               SyncSingleton syncSingleton1 = (SyncSingleton) constructor.newInstance();
               SyncSingleton syncSingleton2 = (SyncSingleton) constructor.newInstance();
               System.out.println("破解后:"+ (syncSingleton1 == syncSingleton2 ? "是同一对象" : "不是同一对象"));
          }catch(Exception e){
                e.printStackTrace();
          }
      }
    }
    

      测试结果

    破解前: 是同一对象!
    破解后:不是同一个对象
    

    相关文章

      网友评论

          本文标题:单例(饿汉、懒汉、静态内部类、枚举)

          本文链接:https://www.haomeiwen.com/subject/znotuhtx.html