精华内容
下载资源
问答
  • 主要介绍了 JAVA 枚举单例模式及源码分析的实例详解的相关资料,需要的朋友可以参考下
  • * 枚举单例 线程池 如果多处使用该方法,则不可以shutDown */ public enum EnumThread { /** * 线程(单例不可以创建两个枚举实例,如果常见两个枚举实力,执行是,会调用两次想要单例的方法) */ EXECUTOR_...
    /**
     * 枚举单例 线程池 如果多处使用该方法,则不可以shutDown
     */
    public enum EnumThread {
    
        /**
         * 线程(单例不可以创建两个枚举实例,如果常见两个枚举实力,执行是,会调用两次想要单例的方法)
         */
        EXECUTOR_POOL;//因为枚举实例变量需要枚举类的构造器创建,所以,构造器没有形参,枚举实例参数EXECUTOR_POOL 也不用写成 
                      //EXECUTOR_POOL("参数") 该形式,;                    
    
        /**
         * ExecutorService 接口作为返回类型
         */
        private final ExecutorService maxExecutor;
        private final ExecutorService minExecutor;
    
        EnumThread() {
            System.out.println("11");
            ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("funinbook-pool-%d").build();
            maxExecutor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE67,
                    CORE_POOL_SIZE87,
                    10,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingDeque<Runnable>(1024),
                    namedThreadFactory,
                    new ThreadPoolExecutor.AbortPolicy()
            );
            minExecutor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE7,
                    CORE_POOL_SIZE27,
                    10,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingDeque<Runnable>(1024),
                    namedThreadFactory,
                    new ThreadPoolExecutor.AbortPolicy()
            );
        }
    
        /**
         * 线程数最大77 最小 57
         *
         * @return
         */
        public ExecutorService getMaxExecutor() {
            return maxExecutor;
        }
    
        /**
         * 线程数最大7 最小 7
         *
         * @return
         */
        public ExecutorService getMinExecutor() {
            return minExecutor;
        }
    }
    

     

    下面是测试,用两个枚举实例变量会调用两次想要单例的方法实例

     

    class Test{

    //main 方法调用枚举类10次,会发现“会调用两次”会输出两次,所以,想要用枚举类写单例,一定要像上面那样,只用一个枚举实例
    public static void main(String[] args) {
        for (int i = 0; i <10 ; i++) {
            for (int j = 0; j < 10; j++) {
                ThreadPoolManager.EnumThread.EXECUTOR_POOL.getMaxExecutor();
            }
        }
    }

    /**
     * 枚举单例 线程池 如果多处使用该方法,则不可以shutDown
     */
    public enum EnumThread {
    
        /**
         * 线程(单例不可以创建两个枚举实例,如果常见两个枚举实力,执行是,会调用两次想要单例的方法)
         */
        EXECUTOR_POOL,
        EXECUTOR_POOL_MAX;
    
        /**
         * ExecutorService 接口作为返回类型
         */
        private final ExecutorService maxExecutor;
        private final ExecutorService minExecutor;
    
        EnumThread() {
            System.out.println("会调用两次");
            ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("funinbook-pool-%d").build();
            maxExecutor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE67,
                    CORE_POOL_SIZE87,
                    10,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingDeque<Runnable>(1024),
                    namedThreadFactory,
                    new ThreadPoolExecutor.AbortPolicy()
            );
            minExecutor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE7,
                    CORE_POOL_SIZE27,
                    10,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingDeque<Runnable>(1024),
                    namedThreadFactory,
                    new ThreadPoolExecutor.AbortPolicy()
            );
        }
    
        /**
         * 线程数最大77 最小 57
         *
         * @return
         */
        public ExecutorService getMaxExecutor() {
            return maxExecutor;
        }
    
        /**
         * 线程数最大7 最小 7
         *
         * @return
         */
        public ExecutorService getMinExecutor() {
            return minExecutor;
        }
    }

    }

    展开全文
  • 枚举单例得优点

    2020-11-08 18:17:03
    1.代码简洁 public enum Singleton { INSTENS; } 2.DCL已经是一种线程安全得写法,但是可以...而枚举单例规避了反序列化和反射 3.这种方式是Effective Java作者Josh Bloch 提倡的方式,被认为是单例得最优实现 ...

    1.代码简洁

    public enum  Singleton {
        INSTENS;
    }
    
    

    2.DCL已经是一种线程安全得写法,但是可以被反序列化暴力破解
    而枚举单例规避了反序列化和反射
    3.这种方式是Effective Java作者Josh Bloch 提倡的方式,被认为是单例得最优实现

    展开全文
  • 2 枚举单例使用过吗?它为什么是安全的? 3 Kotlin中的单例有使用过吗? 双重锁定单例 首先我们快速回忆一下双重锁定单例和静态内部类单例,首先双重锁定单例如下: public class Manager { private volatile st.

    单例模式在我们书写代码中是最经常使用的一种设计模式,但是这种设计模式真的安全吗?如果不安全的话,我们有没有安全的单例模式?其实这也是大厂面试的时候可能会问道的面试题,本篇我们来研究下这个问题。

    引出问题

    1 双重锁定单例和静态内部类单例安全吗?

    2 枚举单例使用过吗?它为什么是安全的?

    3 Kotlin中的单例有使用过吗?


    双重锁定单例

    首先我们快速回忆一下双重锁定单例和静态内部类单例,首先双重锁定单例如下:

    public class Manager {
        private volatile static Manager INSTANCE = null;
    
        private Manager() {
        }
    
        public static Manager getInstance() {
            if (INSTANCE == null) {//第一次判空
                synchronized (Manager.class) {
                    if (INSTANCE == null) {//第二次判空
                        INSTANCE = new Manager();
                    }
                }
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            Manager instance = Manager.getInstance();
            Manager instance2 = Manager.getInstance();
            System.out.println(instance);//com.oman.forward.pattern.create.singleton.Manager@5ca881b5
            System.out.println(instance2);//com.oman.forward.pattern.create.singleton.Manager@5ca881b5
            System.out.println(instance == instance2);//true
        }
    }
    

    为什么要两次判空呢?因为假如两个线程都走到了锁的地方,第一个线程持有了锁之后,内部判断为空,创建实例成功后释放锁。此时第二个线程获取到了锁,假如没有第二个判空条件,很明显就又会再次实例化一次对象,那么所谓的单例就不是全局唯一的了。

    为什么加上volatile关键字?主要为了避免指令排序导致的问题,因为对象的创建最少需要三个步骤:1 在堆内存开辟内存控件;2 内存控件的初始化零值;3 将实例化的对象指向栈中的符号引用。如果不加上volatile的话,可能会导致步骤2和3的执行顺序得不到保证,假如线程1先执行了步骤1和步骤3,此时线程2在外部第一次判断不为空,就去直接使用单例对象了,就会出现问题。


    静态内部类单例

    下面看静态内部类的方式创建的单例:

    public class Manager2 {
        private Manager2() {
        }
    
        private static class SingletonHolder {
            private static final Manager2 INSTANCE = new Manager2();
        }
    
        public static Manager2 getInstance() {
            return SingletonHolder.INSTANCE;
        }
    
        public static void main(String[] args) {
            Manager2 instance = Manager2.getInstance();
            Manager2 instance2 = Manager2.getInstance();
            System.out.println(instance); //com.oman.forward.pattern.create.singleton.Manager2@5ca881b5
            System.out.println(instance2);//com.oman.forward.pattern.create.singleton.Manager2@5ca881b5
            System.out.println(instance == instance2);//true
        }
    }
    

    静态内部类方式创建单例也是通过懒加载的方式创建的单例,因为静态内部类不属于JVM规定的必须进行初始化的情况,只有在调用getInstance静态方法的时候才会进行内部类的初始化,保证了类的延迟加载,不浪费资源。

    并且虚拟机会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。如果在一个类的<clinit>()方法中有耗时很长的操作,就可能造成多个进程阻塞(需要注意的是,其他线程虽然会被阻塞,但如果执行<clinit>()方法后,其他线程唤醒之后不会再次进入<clinit>()方法。同一个加载器下,一个类型只会初始化一次)。

    所以可以看出INSTANCE在创建过程中是线程安全的,所以说静态内部类形式的单例可保证线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

    但是静态内部类单例有一个很大的问题就是不能传递参数,如果需要传递参数的话,就不能使用这种方式创建单例了。

    以上两种单例是安全的吗?

    下面我们通过代码来演示:

    public static void main(String[] args) throws Exception {
            Manager instance = Manager.getInstance();
            Manager instance2 = Manager.getInstance();
            System.out.println(instance);//com.oman.forward.pattern.create.singleton.Manager@5ca881b5
            System.out.println(instance2);//com.oman.forward.pattern.create.singleton.Manager@5ca881b5
            System.out.println(instance == instance2);//true
    
            Constructor<Manager> constructor = Manager.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Manager manager = constructor.newInstance();
            System.out.println(manager);//com.oman.forward.pattern.create.singleton.Manager@24d46ca6
            System.out.println(instance == manager);//false
    }
    

    从代码可以看出,我们通过反射又可以重新创建一个单例对象的实例,并且和原来的地址值不是同一个(静态内部类的单例可以通过同一种方式验证),那这样的话单例还安全吗?


    枚举:安全的单例

    我们使用枚举来创建单例,看看效果如何,是否安全

    public enum EnumSingle {
        INSTANCE;
    
        public void test() {
            System.out.println("test");
        }
    
        public static void main(String[] args) throws Exception {
            EnumSingle single = EnumSingle.INSTANCE;
            EnumSingle single2 = EnumSingle.INSTANCE;
            System.out.println(single);//INSTANCE
            System.out.println(single2);//INSTANCE
            System.out.println(single == single2);//true
        }
    }
    

    上面的结果并不能说明什么,我们也使用反射获取一下单例,看看效果如何?

    public static void main(String[] args) throws Exception {
        Constructor<EnumSingle> enumSingleConstructor = EnumSingle.class.getDeclaredConstructor();
        enumSingleConstructor.setAccessible(true);
        EnumSingle enumSingle = enumSingleConstructor.newInstance();
        System.out.println(enumSingle);
    }
    

    上述代码在运行的时候会报错如下,
    Exception in thread "main" java.lang.NoSuchMethodException: com.oman.forward.pattern.create.singleton.EnumSingle.<init>() at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.getDeclaredConstructor(Class.java:2178) at com.oman.forward.pattern.create.singleton.EnumSingle.main(EnumSingle.java:13),

    在debug的时候发现,只有一个参数为(String.class,int.class)构造器,其实看下父类Enum源码就明白,这两个参数是name和ordial两个属性:
    在这里插入图片描述
    那么我们使用这两个参数的构造方法使用反射获取一下,看看效果,于是代码改成了下面这样:

     public static void main(String[] args) throws Exception {
        Constructor<EnumSingle> enumSingleConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        enumSingleConstructor.setAccessible(true);
        EnumSingle enumSingle = enumSingleConstructor.newInstance("name",1);
        System.out.println(enumSingle);
    }
    

    运行一下看看效果如何?
    Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at com.oman.forward.pattern.create.singleton.EnumSingle.main(EnumSingle.java:15)

    从上面我看到还是会报错,不过报错的内容变为了Cannot reflectively create enum objects,查看源码newInstance,如下:

    public T newInstance(Object ... initargs)
            throws InstantiationException, IllegalAccessException,
                   IllegalArgumentException, InvocationTargetException
        {
            if (!override) {
                if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                    Class<?> caller = Reflection.getCallerClass();
                    checkAccess(caller, clazz, null, modifiers);
                }
            }
            if ((clazz.getModifiers() & Modifier.ENUM) != 0)
                throw new IllegalArgumentException("Cannot reflectively create enum objects");
            ConstructorAccessor ca = constructorAccessor;   // read volatile
            if (ca == null) {
                ca = acquireConstructorAccessor();
            }
            @SuppressWarnings("unchecked")
            T inst = (T) ca.newInstance(initargs);
            return inst;
    }
    

    我们能看到报错是源自于下面这一行,说明了java虚拟机不允许对枚举进行反射。从而说明枚举是安全的单例。

    if ((clazz.getModifiers() & Modifier.ENUM) != 0)
                throw new IllegalArgumentException("Cannot reflectively create enum objects");
    

    说到这里,其实我们可以完全按照java虚拟机的这种思想,对我们的单例设置安全性,代码如下:

    public class Manager {
        private volatile static Manager INSTANCE = null;
    
        private Manager() {
            if ((this.getClass().getModifiers() & Modifier.PUBLIC) != 0) {
                throw new IllegalArgumentException("Cannot reflectively create this objects");
            }
        }
    
        public static Manager getInstance() {
            if (INSTANCE == null) {
                synchronized (Manager.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new Manager();
                    }
                }
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) throws Exception {
            Constructor<Manager> constructor = Manager.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Manager manager = constructor.newInstance();
        }
    }
    

    这样在运行上述代码的时候,就会报错,不允许反射创建实例了,保证了单例的全局唯一并且安全性。

    其实单例模式在序列化的时候也会有一些问题:
    首先看单例的序列化和反序列化问题:

    public class Manager implements Serializable {
    
        private static final long serialVersionUID = 36249882076318126L;
    
        private volatile static Manager INSTANCE = null;
    
        private Manager() {
        }
    
        public static Manager getInstance() {
            if (INSTANCE == null) {
                synchronized (Manager.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new Manager();
                    }
                }
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) throws Exception {
            Manager instance = Manager.getInstance();
            Manager instance2 = Manager.getInstance();
            System.out.println(instance);//com.oman.forward.pattern.create.singleton.Manager@5ca881b5
            System.out.println(instance2);//com.oman.forward.pattern.create.singleton.Manager@5ca881b5
            System.out.println(instance == instance2);//true
    
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("obj"));
            outputStream.writeObject(instance);
            outputStream.flush();
            outputStream.close();
    
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("obj"));
            Manager m = (Manager) objectInputStream.readObject();
            objectInputStream.close();
            System.out.println(m);//com.oman.forward.pattern.create.singleton.Manager@4edde6e5
            System.out.println(instance == m);//false
        }
    }
    

    我们看到反序列化后的对象和原来对象不一致。我们再来看看枚举的序列化和反序列化:

    public enum EnumSingle {
        INSTANCE;
    
        public void test() {
            System.out.println("test");
        }
    
        public static void main(String[] args) throws Exception {
            EnumSingle single = EnumSingle.INSTANCE;
            EnumSingle single2 = EnumSingle.INSTANCE;
            System.out.println(single);//INSTANCE
            System.out.println(single2);//INSTANCE
            System.out.println(single == single2);//true
    
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("single"));
            outputStream.writeObject(single);
            outputStream.flush();
            outputStream.close();
    
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("single"));
            EnumSingle m = (EnumSingle) objectInputStream.readObject();
            objectInputStream.close();
            System.out.println(m);//INSTANCE
            System.out.println(single == m);//true
        }
    }
    

    从运行结果来看,序列化前和序列化后是同一个对象。


    那么我们需要思考一下,为什么枚举能够保证线程安全?

    其实枚举反编译后是继承自Enum类的,当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的(因为虚拟机在加载枚举的类的时候,会使用ClassLoader的loadClass方法,而这个方法使用同步代码块保证了线程安全)。所以,创建一个enum类型是线程安全的。

    另外枚举如何保证序列化后还是同一个对象的?

    因为在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。

    普通的Java类的反序列化过程中,会通过反射调用类的默认构造函数来初始化对象。所以,即使单例中构造函数是私有的,也会被反射给破坏掉。但是,枚举的反序列化并不是通过反射实现的。所以,也就不会发生由于反序列化导致的单例破坏问题。


    Kotlin中的单例(这里只简单介绍两种)

    饿汉式单例:
    kotlin中的饿汉式单例只需要一个object关键字就可以实现,不信的话我们反编译看看字节码:

    object Single
    

    反编译后的class文件如下, 说明确实是饿汉式的单例。

    public final class Single {
       public static final Single INSTANCE;
    
       private Single() {
       }
    
       static {
          Single var0 = new Single();
          INSTANCE = var0;
       }
    }
    

    懒加载单例, 其实这里使用的是kotlin的延迟属性lazy, 关于这个属性的具体内容大家可以自行学习。

    class Single private constructor() {
        companion object {
            val instance: Single by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
                Single()
            }
        }
    }
    
    展开全文
  • enum枚举单例的使用

    千次阅读 2019-06-13 22:20:27
    使用情景:java调用dll,在调用dll里面的接口之前,要先调用初始化函数;而这个初始化函数每次都需要执行1分钟才执行完,如果每次调用... * enum枚举单例的使用 */ public enum PictureUtil { INSTANCE; private...

    使用情景:java调用dll,在调用dll里面的接口之前,要先调用初始化函数;而这个初始化函数每次都需要执行1分钟才执行完,如果每次调用接口之前都调用一次初始化函数,显然太过浪费时间,很影响用户体验;故用单例模式解决此问题。

    1.创建单例类:

    /**
     * enum枚举单例的使用
     */
    public enum PictureUtil {
    
        INSTANCE;
        private boolean isInit = false;
    
        private int init() {    //初始化函数,耗时较长
            System.out.println("开始初始化...");
            try {//模拟消耗资源
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int result = 0;//初始化成功返回0
            if(result == 0){
                isInit = true;
            }
            return result;
        }
    
        public int transfer(){  //转换函数
            if(!isInit){
                int res = init();
                System.out.println("核心初始化结果:"+res);
            }
            System.out.println("开始转换...");
            return 0;
        }
    
        public static void main(String[] args) {
            //在其他类使用示例
            PictureUtil pictureUtil = PictureUtil.INSTANCE;//获取单例
            pictureUtil.transfer();//转换函数
        }
    }
    

    2.在controller里面调用单例的方法

    package com.example.demo2.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class helloController {
        @RequestMapping("/haha")
        public String haha() {
            PictureUtil pictureUtil = PictureUtil.INSTANCE;//获取单例
            int result = pictureUtil.transfer();
            return "成功:"+result;
        }
    }
    

    结果:

    多次访问http://localhost:8080/haha

    第一次访问后台打印的是:【先执行初始化函数,在执行转换函数】

    开始初始化...
    核心初始化结果:0
    开始转换...

    第二次以及之后的访问后台打印的是:【直接执行转换函数,省去了执行初始化函数的时间】

    开始转换...

    总结使用方法:

    public enum SingletonDemo4 {
         
        //枚举元素本身就是单例
        INSTANCE;
         
        //添加自己需要的操作
        public void singletonOperation(){     
        }
    }

     

    展开全文
  • java 枚举单例

    千次阅读 2019-03-14 16:29:53
    * 所有的枚举类型隐性地继承自java.lang.Enum 。 * 枚举实质上还是类!而每个枚举的成员实质就是一个枚举类型的实例, * 他们默认都是public static final 修饰的。可以直接通过枚举类型名使用它们。 * 建议: ...
  • Java枚举单例

    千次阅读 2016-02-28 17:23:47
    不要仅仅只将enum当做一个枚举来使用,除了枚举的特性之外它还能做一些其他工作,包括可以使用成员变量和声明自己的方法等,例如: public enum EnumInstance { INSTANCE; private EnumInstance() { ...
  • * 单例模式有以下特点: * 1、单例类只能有一个实例。 * 2、单例类必须自己创建自己的唯一实例。 * 3、单例类必须给所有其他对象提供这一实例。 * @Author: trc * @Date: 2020-07-31 14:37 */ public class ...
  • 单例枚举实现在《Effective Java》中有提到,因为其功能完整、使用简洁、无偿地提供了序列化机制、在面对复杂的序列化或者反射攻击时仍然可以绝对防止多次实例化等优点,单元素的枚举类型被作者认为是实现...
  • 枚举单例模式具有以下三个优点: 1、写法简洁,代码短小精悍。 2、线程安全。 3、防止反序列化和反射的破坏。 Joshua Bloch 在《Effective Java》中明确表明,枚举类型实现的单例模式是最佳的方式。
  • 前言: 单例模式是最常见的设计模式了,无论在面试还是真正的工作时也会大量遇到单例模式,单例模式有懒汉饿汉,双重检查锁,静态...枚举单例模式代码: public enum Singleton { INSTANCE; public void wha...
  • 单例模式 ​ 保证一个类在任何情况下都绝对只有一个实例,并且提供一个全局访问点 ​ 需要隐藏其所有构造方法 ​ 优点: ​ 在内存中只有一个实例,减少了内存开销 ​ 可以避免对资源的多重占用 ​ 设置全局访问...
  • 双重检测锁模式 作用:这个模式通过将同步...作用:通过在类的内部加入一个静态的内部类的方法进行对类的单例化(在内部类中利用final和static来保证单例)。这种方法在使用的过程中,因为其类在加载时并不会立即加载静
  • 单例最基本要素: 私有静态属性,用于存取类的唯一实例。 公共静态方法,用于提供对该唯一实例的存取访问,如果实例未创建,则创建该实例。 用于限制类再次实例化的方式。通常使用私有构建函数的方式来实现。 最...
  • 展示下枚举单例代码: package com.self.entity; public enum LogSingleton { LOG("TE",0); private String name; private int count; LogSingleton(String name, int count) { this.name = name; this....
  • 枚举单例模式比DCL和静态单例模式要好?为什么好呢?本文带你一探究竟!
  • package demo;...最重要的是默认枚举实例的创建是现成安全的,并且在任何情况下都是一个单例。 前几篇文章的枚举方式中反序列化依然可以创建一个新的实例。 反序列化提供了一个特别的钩子函数,
  • 饿汉式(单例对象立即加载)实现方式二:懒汉式(单例对象延迟加载)实现方式三:双重检测锁实现(不建议使用)实现方式四:静态内部类实现方式(懒加载方式)实现方式五:枚举单例模式总结 设计模式简介 将设计者的...
  • 前言 关于单例模式,作为23种设计模式中最为常用的设计模式,单例模式并没有想象的那么简单。...二、其他单例模式与枚举对比 下面举一种线程安全的单例枚举做对比 1、“双重校验锁”实现单例: public clas...
  • 枚举单例yyds之单例模式没有那么简单

    千次阅读 多人点赞 2021-03-08 20:22:07
    枚举单例yyds——单例模式没有那么简单前言一、饿汉与懒汉——得不偿失的改变二、使用步骤1.引入库2.读入数据总结 前言 我相信大多程序员同胞们第一个接触的设计模式就是在大学课堂上讲到的单例模式,功能目的很...
  • 枚举单例(Enum Singleton)

    千次阅读 2017-08-18 11:47:21
    枚举单例(Enum Singleton)是实现单例模式的一种新方式,尽管单例模式在java中已经存在很长时间了,但是枚举单例相对来说是一种比较新的概念,枚举这个特性是在Java5才出现的,这篇文章主要讲解关于为什么我们应该...
  • 枚举单例的实现

    2020-03-18 14:50:56
    枚举单例的实现 单例是什么我在这里不再详细说了,其他的饿汉模式单例、懒汉模式单例、双重加锁这么的在此都不讨论。我参考了网上其他人写的枚举单例,都差不多,没什么实用的参考价值,这里只给出我自己实现的枚举...
  • 一、Enum枚举单例模式 1、 定义一个枚举类 package com.rf.designPatterns.singleton.enumSingleton; /** * @description: 定义一个枚举类 * @author: xiaozhi * @create: 2020-06-01 20:50 * 枚举类的单例模式...
  • 枚举单例

    2015-12-23 10:15:14
    声明枚举实例的通常做法: /** * Singleton pattern example using Java Enumj */ public enum EasySingleton{ INSTANCE; } 通过EasySingleton.INSTANCE来访问 DCL实现: /** * Singleton pattern example with ...
  • 说到单例首先要提到单例模式,因为单例模式是单例存在的目的 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于...
  • 枚举类: public enum EnumSingleTon { /** * 唯一实例 */ uniqueEnum(),; } 主函数: public static void main(String[] args) throws Exception { EnumSingleTon uniqueEnum = EnumSingleTon.un...
  • 单例模式之枚举单例

    2020-08-20 13:32:17
    * 枚举单例 */ // 问题1:枚举单例是如何限制实例个数的 =>反编译后可以看到 就是我们枚举类的一个静态成员变量而已,单实例的 // 问题2:枚举单例在创建时是否有并发问题 // =>没有,因为它也是静态成员...
  • java枚举单例

    2020-04-23 18:51:07
    new SingleInstance SingleInstance method SingleInstance method SingleInstance method SingleInstance method SingleInstance method ...finished with exit code 0 所以枚举单例是线程安全并且是用时再加载的
  • 枚举单例类简单实践

    2019-01-07 20:34:44
    《Effective Java》作者推荐枚举实现单例类 ---享有特权的客户端可以借助AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。如果需要抵御这种攻击,可以修改构造器,让它在被要求创建第二个实例的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 46,673
精华内容 18,669
关键字:

枚举单例