zoukankan      html  css  js  c++  java
  • 最简单的设计模式——单例模式


    单例模式可以说是最简单也是最常见的设计模式了,有些语言比如scala甚至在语言层面对其进行了支持。单例是指类的实例在全局只有一个。什么时候我们希望类的实例在整个JVM进程中只有一个?比如说线程池:创建开销很大;还有缓存:占用内存空间很多,而且超过一个也不利于维护。还有其他比如注册表对象,日志对象等等我们都希望它们全局唯一。单例模式指导我们如何创建这样一个对象。

    2. 单例模式详解

    2.1 单例模式定义

    确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

    2.2 单例模式类结构

    2.3 单例模式实现

    单例的实现有很多种,按单例对象是否延迟初始化可以分为懒汉是和饿汉式。每一种的实现又有两种变体。

    2.3.1常规饿汉式实现

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

    通过一个静态变量引用单例实例,该变量在类加载的时候就会初始化,线程安全。

    2.3.2 枚举饿汉式实现

    public enum  Singleton {
        INSTANCE
    }
    

    枚举类型的本质如下,区别仅在于静态变量是公有的,同样也是线程安全。

    public class Singleton extends Enum<Singleton> {
        public static final Singleton INSTANCE = new Singleton();
    }
    
    

    2.3.3 使用静态内部类的懒汉式实现

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

    只有在调用getInstance方法时才会加载静态内部类SingletonHolder,该内有一个静态成员变量,该成员变量在类加载的时候初始化,指向一个单例对象。同样也线程安全。

    2.3.4 带双重检查的懒汉式实现

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

    这是所有实现方式中最重要的。倒不是因为它平时用的多(大部分情况下直接用常规的饿汉式单例就行了),而是因为面试的时候经常会被问到,很多时候甚至会让面试者把它现场手写出来。因为其本身并不复杂,但能很好的考察对多线程的理解程度。而且以volitile,线程同步,类加载机制为入口可以深入考察多线程和jvm领域更深入的知识。比如:
    1.volitile在这里有什么用?你知道它还有什么功能吗?它是否能保证线程安全?它的底层是怎么实现的?

    2.为什么要在方法内加同步代码块?可以把同步关键字放在方法上吗?它和前一种有什么区别?你觉得哪个更好?

    可惜我在上家公司用这个问题面了不少3年左右开发经验求职者,能把这部分代码大概写对的都不到20%。可能因为我面的都是大数据开发工程师吧,java基础会薄弱些。

    参考资料
    -《设计模式之禅》

  • 相关阅读:
    jQuery Easyui Datagrid相同连续列合并扩展
    Codeforces 240F. TorCoder 线段树
    java基础—Hashtable,HashMap,TreeMap的差别
    Android 屏幕适配扫盲、教程
    spring(13)------全面深入解析spring的AOP
    STL中的二分查找——lower_bound 、upper_bound 、binary_search
    闭包
    HDU 4193 Non-negative Partial Sums(单调队列)
    设计模式--基础学习总结
    代码坏味道特征反复的代码
  • 原文地址:https://www.cnblogs.com/takumicx/p/9270789.html
Copyright © 2011-2022 走看看