单例模式的要点(写出一个单例模式)

目录一、单例模式的定义和应用场景(一)定义及基本要点(二)应用场景二、饿汉式单例模式(一)基本代码展示分析(二)基本分析和建议三、懒汉式单例模式(双重检查锁)(一)基本代码展示分析(二)基本分析和建议四、静态内部类实现单例模式(一)基本代码展示分析(二)基本分析和建议五、注册式单例模式(一)枚举式单例模式代码及分析:(EffectiveJa…

大家好,又见面了,我是你们的朋友全栈君。

目录

一、单例模式的定义和应用场景

(一)定义及基本要点

(二)应用场景

二、饿汉式单例模式

(一)基本代码展示分析

(二)基本分析和建议

三、懒汉式单例模式(双重检查锁)

(一)基本代码展示分析

(二)基本分析和建议

四、静态内部类实现单例模式

(一)基本代码展示分析

(二)基本分析和建议

五、注册式单例模式

(一)枚举式单例模式代码及分析:(Effective Java推荐单例模式)

(二)容器式单例模式代码及分析:(适用于实例非常多的情况,便于管理,但是是非线程安全的)

参考书籍、文献和资料


一、单例模式的定义和应用场景

(一)定义及基本要点

单例模式是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。

该模式有三个基本要点

  • 一是这个类只能有一个实例;
  • 二是它必须自行创建这个实例;
  • 三是它必须自行向整个系统提供这个实例。

(二)应用场景

应用场景:J2EE中的ServlertContext、SerletContextConfig等、Spring框架应用中的ApplicationContext、数据库连接池等。

二、饿汉式单例模式

(一)基本代码展示分析

/**
 * 描述:饿汉式单例模式
 * 优点:没有任何锁,执行效率高,用户体验比懒汉式单例模式更好
 * 缺点:类加载的时候就初始化,不管用不用都占内存空间
 * 建议:适用于单例模式较少的场景
 *      如果我们在程序启动后,一定会加载到类,那么用饿汉模式实现的单例简单又实用;
 *      如果我们是写一些工具类,则优先考虑使用懒汉模式,可以避免提前被加载到内存中,占用系统资源。
 *
 * @author yanfengzhang
 * @date 2020-01-02 20:39
 */
public class HungrySingleton {
    private final static HungrySingleton HUNGRY_SINGLETON = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton getInstance() {
        return HUNGRY_SINGLETON;
    }
}

(二)基本分析和建议

优点:没有任何锁,执行效率高,用户体验比懒汉式单例模式更好
缺点:类加载的时候就初始化,不管用不用都占内存空间
建议:

  • 适用于单例模式较少的场景
  • 如果我们在程序启动后,一定会加载到类,那么用饿汉模式实现的单例简单又实用;
  • 如果我们是写一些工具类,则优先考虑使用懒汉模式,可以避免提前被加载到内存中,占用系统资源。

三、懒汉式单例模式(双重检查锁)

(一)基本代码展示分析

/**
 * 描述:懒汉式单例模式---双重检查锁
 * 相比单锁而言,双重检查锁性能上虽然有提升,但是依旧用到了synchronized关键字总归要上锁,对程序性能还是存在一定的性能影响
 * 不算最优--存在优化空间
 *
 * 建议:如果我们在程序启动后,一定会加载到类,那么用饿汉模式实现的单例简单又实用;
 *      如果我们是写一些工具类,则优先考虑使用懒汉模式,可以避免提前被加载到内存中,占用系统资源。
 *
 * @author yanfengzhang
 * @date 2020-01-02 20:53
 */
public class LazyDoubleCheckSingleton {
    /**
     * volatile 关键字可以保证线程间变量的可见性,还有一个作用就是阻止局部重排序的发生
     */
    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;

    private LazyDoubleCheckSingleton() {
    }

    public static LazyDoubleCheckSingleton getInstance() {
        if (null == lazyDoubleCheckSingleton) {
            synchronized (LazyDoubleCheckSingleton.class) {
                if (null == lazyDoubleCheckSingleton) {
                    lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
                }
            }
        }
        return lazyDoubleCheckSingleton;
    }
}

(二)基本分析和建议

相比单锁而言,双重检查锁性能上虽然有提升,但是依旧用到了synchronized关键字总归要上锁,对程序性能还是存在一定的性能影响。注意里面volatile的使用!!!

建议:

  • 如果我们在程序启动后,一定会加载到类,那么用饿汉模式实现的单例简单又实用;
  • 如果我们是写一些工具类,则优先考虑使用懒汉模式,可以避免提前被加载到内存中,占用系统资源。

四、静态内部类实现单例模式

(一)基本代码展示分析

/**
 * 描述:屏蔽饿汉式单例模式的内存浪费问题和双重检查锁中synchronized的性能问题
 * 避免因为反射破坏单例
 *
 * @author yanfengzhang
 * @date 2020-01-02 21:08
 */
public class LazyInnerClassSingleton {
    /**
     * 使用LazyInnerClassSingleton的时候会先默认初始化换内部类
     * 如果没有使用,则内部类是不加载的
     */
    private LazyInnerClassSingleton() {
        /*为了避免反射破坏单例,需要在构造方法中增加限制,一旦出现多次重复创建,直接抛出异常*/
        if (null != Lazyholder.LAZY_INNER_CLASS_SINGLETON) {
            throw new RuntimeException("创建LazyInnerClassSingleton异常,不允许创建多个实例!");
        }
    }

    /**
     * 每一个关键字都不是多余的,static是为了使单例的空间共享,保证这个方法不会被重写、重载
     */
    public static final LazyInnerClassSingleton getInstance() {
        /*在返回结果前,一定会先加载内部类*/
        return Lazyholder.LAZY_INNER_CLASS_SINGLETON;
    }

    /**
     * 默认不加载
     */
    private static class Lazyholder {
        private static final LazyInnerClassSingleton LAZY_INNER_CLASS_SINGLETON = new LazyInnerClassSingleton();
    }
}

(二)基本分析和建议

屏蔽饿汉式单例模式的内存浪费问题和双重检查锁中synchronized的性能问题,同时考虑避免因为反射破坏单例问题。

相对而言性能最好!

五、注册式单例模式

注册式单例模式/登记式单例模式,将每个实例都登记到一个地方,使用唯一的标识获取单例。

注册单例模式有两种:枚举式单例模式+容器式单例模式

(一)枚举式单例模式代码及分析:(Effective Java推荐单例模式)

/**
 * 描述:注册式单例模式/登记式单例模式,将每个实例都登记到一个地方,使用唯一的标识获取单例。
 * 注册单例模式有两种:枚举式单例模式+容器式单例模式
 * 此为枚举式单例模式---Effective Java推荐单例模式
 *
 * @author yanfengzhang
 * @date 2020-01-03 09:59
 */
public enum EnumSingleton {
    /*枚举式单例模式*/
    INSTANCE;

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance() {
        return INSTANCE;
    }
}

(二)容器式单例模式代码及分析:(适用于实例非常多的情况,便于管理,但是是非线程安全的)

/**
 * 描述:注册式单例模式/登记式单例模式,将每个实例都登记到一个地方,使用唯一的标识获取单例。
 * 注册单例模式有两种:枚举式单例模式+容器式单例模式
 * 建议:容器式单例模式适用于实例非常多的情况,便于管理,但是是非线程安全的。
 *
 * @author yanfengzhang
 * @date 2020-01-03 10:51
 */
public class ContainerSingleton {
    private ContainerSingleton() {
    }

    private static Map<String, Object> ioc = new ConcurrentHashMap<>();

    public static Object getBean(String className) {
        synchronized (ioc) {
            if (ioc.containsKey(className)) {
                return ioc.get(className);
            }
            Object obj = null;
            try {
                obj = Class.forName(className).newInstance();
                ioc.put(className, obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;
        }
    }
}

 

参考书籍、文献和资料

1.《Sring 5 核心原理与30个类手写实战》,谭勇徳,中国公信出版社,2019.

2.极客时间课程《Java性能调优实战》,刘超,2019.

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/125954.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • linux定时执行shell脚本「建议收藏」

    linux定时执行shell脚本「建议收藏」写一个shell脚本,定时执行简单示例很多时候我们有希望服务器定时去运行一个脚本来触发一个操作,比如说定时去备份服务器数据、数据库数据等不适合人工经常做的一些操作这里简单说下 Shell俗称壳,类似于DOS下的command和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程…

  • linux定时删除N天前的文件(文件夹)

    linux定时删除N天前的文件(文件夹)

  • slam关键技术_深度技术还做系统吗

    slam关键技术_深度技术还做系统吗本文由图像处理知识库整理SLAM(simultaneouslocalizationandmapping),也称为CML(ConcurrentMappingandLocali…

  • Mayavi入门_乐理知识入门

    Mayavi入门_乐理知识入门环境,win7/1064位,python3.x1,安装Mayavi4.6原装的pip下载奇慢,先更换一下源,豆瓣的更新要比清华的快首先在window的文件夹窗口输入:%APPDATA%

  • win10键盘锁住了怎么解决

    win10键盘锁住了怎么解决有win10系统用户在使用的时候,发现键盘被锁住了,导致无法使用,经过分析可能是不小心按到了键盘上的锁住键锁定键盘的快捷键笔记本电脑:Fn+Numlock键第一种方法:1、外接键盘,是否按过“Numlock”键,如果按过“Numlock”键,再次使用外接键盘按一次“Numlock”键,就会恢复正常了。(仅仅锁定或者解锁数字键盘)2、可以在电脑键盘中找到“Fn”键,这个键又被称为“第二功能键”,因为当你按下这个键,再去按另一个带有两种功能的键时,那个键就会出现第二种功能。3、再找到“F.

  • pycharm输入框不跟随光标_python光标变粗了

    pycharm输入框不跟随光标_python光标变粗了返回上次编辑的地方:ctrl+shift+backspace(删除返回上次光标

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号