zoukankan      html  css  js  c++  java
  • 五、单例模式(Singleton Pattern)《HeadFirst设计模式》读书笔记

      1.单例模式的定义:确保一个类只有一个实例,并提供一个全局访问点。

        编写单例实例的要点是:

        1)将构造方法私有化,确保别的类不能通过构造方法创建对象;

        2)在本类中通过私有化的构造方法创建对象;

        3)提供一个静态方法让其它类可以获取这个对象。

        使用静态方法是因为普通方法要通过对象来调用,而其它类不能获取到对象,所以只能通过静态方法调用。

      2.单例模式可以分为两种类型:饿汉式和懒汉式。

        1)饿汉式

          饿汉式非常饥渴,在类初始化时就已经将对象创建好了。

    public class HungerSingleton {
        private static HungerSingleton singleton = new HungerSingleton();
        private HungerSingleton(){
        }
        public static HungerSingleton getInstance() {
            return singleton;
        }
    }

          饿汉式同样可以用枚举来简洁的实现:

    public enum SingletonEnum {
        INSTANCE
    }

          在该枚举中只声明一个INSTANCE变量,它就是单例的,使用时可以通过枚举类名.变量名来调用。

        2)懒汉式

          懒汉式非常懒,只有在其它类调用了获取对象的方法时才创建对象,其实就是懒加载。

    public class LazySingleton {
        private static LazySingleton singleton;
        private LazySingleton(){
        }
        public static LazySingleton getInstance() {
            //判断Singleton对象是否已经创建,如果为null就先创建,不为null就直接返回
            if (singleton == null) {
                singleton = new LazySingleton();
            }
            return singleton;
        }
    }

      3.懒汉式单例模式的问题和改进

        在多线程的环境下,如果多个线程想要获取对象实例,可能会产生线程安全问题:如果线程A判断singleton==null后释放了CPU的使用权,由线程B再执行全部过程,则线程B创建好对象之后,线程A又会创建一个新的对象,这样就不是单例了。下面提供了几种解决方法:

        1)对getInstance()方法加上synchronized关键字,这样虽然保证了线程安全,但是效率却大大降低,因为实际上只有第一次Singleton对象为null时才会产生线程安全问题(因为不为null时就直接返回了,不会执行if里面的创建对象代码);

        2)双重检测加锁。在1)的基础上,在synchronized的外层再加一重Singleton对象是否为null的判断,用于第一次为null时对象的创建,同时将类变量声明成volatile,防止指令重排产生的问题。这样只有第一次为null的时候会执行synchronized代码块,后面单例对象已经创建好了会执行外层if里的代码而直接返回了。

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

        3)静态内部类

          在静态内部类中声明静态变量并创建对象,并在单例类中提供获取实例的方法,通过类名.变量名的方式获取到这个唯一的实例,因为只有在该方法被调用时静态内部类才会被加载并创建实例,因此这种方式是一种线程安全的懒汉式单例模式。

    public class InnerStaticClassSingleton {
        private InnerStaticClassSingleton() {
        }
        //静态内部类
        private static class InnerClass{
            private static InnerStaticClassSingleton singleton = new InnerStaticClassSingleton();
        }
        public static InnerStaticClassSingleton getInstance(){
            return InnerClass.singleton;
        }
    }    

      4.总结

        1)单例模式就是将构造方法私有化,再在类内部创建对象并提供获取该对象的静态方法;

        2)单例模式分为懒汉式和饿汉式,懒汉式可能会产生线程安全问题,可以通过加锁或者双重检测或静态内部类来解决。如果并不需要频繁的获取对象,只需要简单的加锁就可以了,效率也不会低太多;

        3)单例的类因为构造方法都是私有化的,因此不能被继承,如果需要继承只能通过修改构造方法的权限修饰符,这就不是严格的单例了;此外单例模式是利用静态变量实现的,继承就意味着所有子类都共享这一变量,因此涉及单例的继承时要谨慎考虑。

  • 相关阅读:
    urlrewrite地址重写的使用
    算法学习
    数据库之Case When
    速卖通返回503错误
    概述:软件开发工具
    c#将List<T>转换成DataSet
    表单域规范写法
    ant打包和jar包混淆
    Node.js文档和教程
    webpack开发和生产两个环境的配置详解
  • 原文地址:https://www.cnblogs.com/advancedcz/p/13207824.html
Copyright © 2011-2022 走看看