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

    概念:

    单例模式(Singleton),也叫单子模式,是一种常用的设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候,整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,显然,这种方式简化了在复杂环境下的配置管理。

    实现方式:

    1.是在调用方法的时候进行实例化的工作,这种方式俗称懒汉模式;

    2.是在类的加载的时候就创建一个实例,这种方式俗称饿汉模式;

    实现单例模式:

    1、懒汉式,线程不安全:

    public class Boss {
        private Boss() {
        }
        private static Boss boss = null;
        public static Boss getBoss(){
            if(boss == null) {
                boss = new Boss();
            }
            return boss;
        }
    }
    
    public static void main(String[] args) {
            ExecutorService pool = Executors.newCachedThreadPool();
            for (int i = 0; i < 20; i++) {
                pool.execute(new Thread(){
                    @Override
                    public void run() {
                        Boss boss = Boss.getBoss();
                        System.out.println(boss);
                    }
                });
            }
        }

    运行结果:

    描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
    这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。

    2、懒汉式,线程安全

    public class Boss {
        private Boss() {
        }
        private static Boss boss = null;
        public static synchronized Boss getBoss(){
            if(boss == null) {
                boss = new Boss();
            }
            return boss;
        }
    }

    运行结果:

    描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
    优点:第一次调用才初始化,避免内存浪费。
    缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。

    3、双重校验锁

    public class Boss {
        private Boss() {
        }
        private static Boss boss = null;
        public static synchronized Boss getBoss(){
            if(boss == null) {
                synchronized (Boss.class){
                    if(boss == null) {
                        boss = new Boss();
                    }
                }
            }
            return boss;
        }
    }
    

    运行结果:

    描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。

    优点:安全且保持高效性。

    4、静态内部类

    public class Boss {
        private Boss() {
        }
    
        static class Lazy{
            private static Boss instance = new Boss();
        }
    
        public static Boss getInstance() {
            return Lazy.instance;
        }
    
    }
    

    运行结果:

    描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
    这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程,它跟第 3 种方式不同的是:第 3 种方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比第 3 种方式就显得很合理。

    三要素: 

    私有的构造方法;
    指向自己实例的私有静态引用;
    以自己实例为返回值的静态的公有方法。

    优点:

    内存中只有一个对象,节省内存空间;
    避免频繁的创建销毁对象,可以提高性能;
    避免对共享资源的多重占用,简化访问;
    为整个系统提供一个全局访问点。

  • 相关阅读:
    Flappy Bird c++试验版
    log4net在windows 2003 iis6下使用的注意事项
    IIS6下, web.config配置为targetFramework="4.0"时出404错误
    mercurial(hg)使用
    Firebird数据库相关备忘录
    关于项目开发进度的看法
    日常数据分析的主要内容仍是结构化计算
    集算器协助java处理多样性数据源之HDFS
    集算器协助Java处理多样性数据源之Hive
    集算器协助java处理多样性数据源之JSON
  • 原文地址:https://www.cnblogs.com/Qi1007/p/9473635.html
Copyright © 2011-2022 走看看