zoukankan      html  css  js  c++  java
  • 单例模式

    简介

    单例模式属于创建者模式。单例类提供了一种访问其内部唯一的对象的方法,可以直接访问,无需实例化该类的对象。

    保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    主要解决:一个全局使用的类频繁地创建与销毁。

    关键在于私有化构造函数

    实现方式

    1.线程不安全的懒汉式实现方式

    懒汉式表示不在一开始就创建对象,在需要的时候再创建

    public class LazyMode {
        /**
         * 私有化构造方法
         */
        private LazyMode() {}
    
        /**
         * 静态私有的实例
         * static保证类没有创建实例也可以用这个实例
         */
        private static LazyMode INSTANCE = null;
    
        /**
         * public的访问单例的方法
         * 这个方法也必须是static的,不然无法返回static的INSTANCE
         *
         * 注意,这个方法是线程不安全的
         */
        public static LazyMode getInstance() {
    
            if (INSTANCE == null){
                INSTANCE = new LazyMode();
            }
    
            return INSTANCE;
        }
    
    }
    

    2.线程安全的懒汉式实现方式

    public class LazyModeSafe {
    
        private LazyModeSafe() {}
    
        private static LazyModeSafe INSTANCE;
    
        public static synchronized LazyModeSafe getInstance() {
            if (INSTANCE == null){
                INSTANCE = new LazyModeSafe();
            }
            
            return INSTANCE;
        }
    }
    

    这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。

    3.饿汉式

    基于 classloader 机制避免了多线程的同步问题,但是没有做到lazy load

    public class HungryMode {
        private HungryMode() {}
    
        private static HungryMode INSTANCE = new HungryMode();
    
        public static HungryMode getInstance() {
            return INSTANCE;
        }
    }
    

    4.双检锁/双重校验锁(DCL,即 double-checked locking)

    public class DoubleCheckMode {
        private static volatile DoubleCheckMode instance;
        private DoubleCheckMode (){
        }
        public static DoubleCheckMode getInstance() {
            if (instance == null) {
                synchronized (DoubleCheckMode.class) {
                    if (instance == null) {
                        instance = new DoubleCheckMode();
                    }
                }
            }
            return instance;
        }
    }
    

    这种写法在getSingleton方法中对singleton进行了两次判空,第一次是为了不必要的同步,第二次是在singleton等于null的情况下才创建实例

    DCL优点是资源利用率高,第一次执行getInstance时单例对象才被实例化,效率高。缺点是第一次加载时反应稍慢一些,在高并发环境下也有一定的缺陷,虽然发生的概率很小。DCL虽然在一定程度解决了资源的消耗和多余的同步,线程安全等问题,但是他还是在某些情况会出现失效的问题,也就是DCL失效,在《java并发编程实践》一书建议用静态内部类单例模式来替代DCL。

    5.静态内部类实现单例模式

    public class StaticInternClass {
    
        private StaticInternClass() {}
    
        private static class LazyHandler {
    
            private static final StaticInternClass INSTANCE = new StaticInternClass();
    
        }
    
        public static StaticInternClass getInstance() {
    
            return LazyHandler.INSTANCE;
    
        }
    }
    

    使用静态内部类持有单例对象

    第一次加载SingletonIntern类时并不会初始化INSTANCE

    只有在第一次调用getInstance方法时虚拟机加载LazyHandler并初始化INSTANCE

    这样不仅利用类加载机制保证了线程安全,还可以实现Lazy Load

    6.枚举模式

    public enum EnumMode {
        INSTANCE;
        public void doSomeThing() {
        }
    }
    

    枚举的方式是比较少见的一种实现方式,但是看上面的代码实现,却更简洁清晰。并且她还自动支持序列化机制,绝对防止多次实例化。

    总结

    使用饿汉式、双检锁、静态内部类这三种模式

  • 相关阅读:
    linux 命令
    linux 命令
    linux 命令
    linux命令
    ubuntu 下安装ssh服务,并修改ssh端口
    爬虫基础
    Django之中间件
    Django之用户认证组件
    Django之cookie&session
    Django之forms组件
  • 原文地址:https://www.cnblogs.com/swifthao/p/13673421.html
Copyright © 2011-2022 走看看