美文网首页
单例模式

单例模式

作者: 恒星_vvv | 来源:发表于2019-10-22 13:44 被阅读0次

    什么是单例设计模式?

    单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。

    单例模式的优点

    1. 由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
    2. 避免对共享资源的多重占用。

    使用场景

    单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:

    1. 需要频繁实例化然后销毁的对象。
    2. 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
    3. 有状态的工具类对象。
    4. 频繁访问数据库或文件的对象。

    Spring中的Bean的创建、数据库连接池的设计、多线程的线程池的设计一般都是采用单例模式。

    单例的具体实现

    1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    2. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型。
    3. 定义一个静态方法返回这个唯一对象。

    一、饿汉式

    饿汉式是立即加载的方式,使用类的时候已经将对象创建完毕,而且不管这个对象在以后会不会使用到,都会在项目启动的时候将对象实例化。

    public class HungrySingleton {
    
        private static final HungrySingleton instance = new HungrySingleton();
    
        private HungrySingleton() {
    
        }
    
        public static HungrySingleton getInstance() {
            return instance;
        }
    }
    

    优点:实现起来简单,没有多线程同步问题。
    缺点:当HungrySingleton该类被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。

    二、懒汉式

    懒汉式不是立即加载的方式,它使用的方式是延迟加载,延迟加载就是调用get()方法时实例才被创建(先不急着实例化出对象,等要用的时候才给你创建出来。不着急,故又称为“懒汉模式”),常见的实现方法就是在get方法中进行new实例化。

    懒汉式包含两种,一种是在方法上加synchronized字段确保线程安全,这种方式每次都会因为抢锁而等待,性能较差;一种是双重校验锁,如果发现对象已经实例化,则直接返回该对象,否则加锁(防止同一时间有多个请求判断,造成多个对象创建),创建对象。

    public class LazySingleton {
    
        private static volatile LazySingleton instance = null;
    
        /**
         * 避免类在外部被实例化
         */
        private LazySingleton() {
    
        }
    
        /**
         * 每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。
         *
         * @return
         */
        public static synchronized LazySingleton getInstance() {
    
            //getInstance 方法前加同步
            if (instance == null) {
                instance = new LazySingleton();
            }
    
            return instance;
        }
    
        /**
         * 认为双重校验锁性能比上面的好一些,不需要每次都同步
         *
         * @return
         */
        public static LazySingleton getInstance2() {
            if (instance == null) {
                synchronized (LazySingleton.class) {
                    if (instance == null) {
                        instance = new LazySingleton();
                    }
                }
            }
    
            return instance;
        }
    
    }
    

    优点:使用synchronized,在多线程情形下,保证了“懒汉模式”的线程安全。
    缺点:众所周知在多线程情形下,synchronized方法通常效率低,显然这不是最佳的实现方案。

    三、静态内部类

    这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在StaticInSingleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类,从而完成Singleton的实例化。

    类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

    public class StaticInSingleton {
        private StaticInSingleton() {
    
        }
    
        private static class SingletonHolder {
            private static StaticInSingleton instance = new StaticInSingleton();
        }
    
        public static StaticInSingleton getInstance() {
            return SingletonHolder.instance;
        }
    }
    

    优点:延迟加载,调用SingletonHolder类时才初始化StaticInSingleton对象,线程安全,效率高。

    四、枚举类

    public enum SingletonEnum {
    
        instance;
    
        private SingletonEnum() {
    
        }
    
        public void method() {
    
        }
    
        public static void main(String[] args) {
            // 访问方式
            SingletonEnum.instance.method();
    
        }
    }
    

    访问很简单在这里SingletonEnum.instance这里的instance即为SingletonEnum类型的引用,所以得到它就可以调用枚举中的方法了。借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。可能是因为枚举在JDK1.5中才添加,所以在实际项目开发中,很少见人这么写过,这种方式也是最好的一种方式,如果在开发中JDK满足要求的情况下建议使用这种方式。

    优点:推荐使用

    参考:
    设计模式之单例模式
    Java单例模式

    相关文章

      网友评论

          本文标题:单例模式

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