Java之单例模式

Java之单例模式

单例模式的优点:

  1. 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要
    比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动
    时直接产生一个单例对象,然后永久驻留内存的方式来解决
  2. 单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计
    一个单例类,负责所有数据表的映射处理
    • 常见的五种单例模式实现方式:
    – 主要:
    • 饿汉式(线程安全,调用效率高。 但是,不能延时加载。)
    • 懒汉式(线程安全,调用效率不高。 但是,可以延时加载。)
    – 其他:
    • 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用)
    • 静态内部类式(线程安全,调用效率高。 但是,可以延时加载) • 枚举单例(线程安全,调用效率高,不能延时加载)

饿汉式实现(单例对象立即加载)

要点: 饿汉式单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。因此,可以省略synchronized关键字。
问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费!

package com.ahzy;
/** * 单例饿汉式 * @author 晓宇码匠 * 频繁的调用这个实例的时候用饿汉式 */
public class SingletonDome01 {
   
    //类初始化时加载这个对象,没有延迟加载的优势,加载类时,是天然的线程安全
    private static SingletonDome01 instance = new SingletonDome01();
    //私有化构造器
    private SingletonDome01(){
      
    }
    //方法没有同步,调用效率高
    public static SingletonDome01 getInstance() {
   
        return instance;
    }
}

懒汉式实现(单例对象延迟加载)

要点: lazy load! 延迟加载, 懒加载! 真正用的时候才加载!
问题:资源利用率高了。但是,每次调用getInstance()方法都要同步,并发效率较低。

package com.ahzy;
/** * 单例懒汉式 * @author 晓宇码匠 * 资源利用率高。但是每次调用getIntance()都要同步,并发效率低 * 当创建实例的代价较大时,用懒汉式 */
public class SingletonDome02 {
   
    private static SingletonDome02 instance;
    private SingletonDome02() {
   
    }
    //方法同步,调用效率低
    public static synchronized SingletonDome02 getInstance(){
   
        //延迟加载,懒加载,真正用的时候再加载
        if(instance==null){
   
            instance = new SingletonDome02();
        }
        return instance;
    }
}

双重检测锁实现

要点:这个模式将同步内容下方到if内部,提高了执行的效率不必每次获取对象时都进行同步,只有第一次才同步创建了以后就没必要了。
问题: 由于编译器优化原因和JVM底层内部模型原因,偶尔会出问题。不建议使用。

package com.ahzy;
/** * 单例双重检测锁模式 * @author 晓宇码匠 * 问题:由于编译器优化原因和JVM底层模式内部原因,偶尔会出现数据调整问题,不建议使用 */
public class SingletonDome03 {
   
    private static SingletonDome03 instance = null;
    private SingletonDome03() {
   }
    /* * 这个模式将同步内容下方到if内部,提高了执行的效率 * 不必每次获得对象时都要进行同步,只有第一次才同步 * 创建了以后就没必要了。 */
    public static SingletonDome03 getInstance() {
   
        if (instance == null) {
   
            SingletonDome03 sc;
            synchronized (SingletonDome03.class) {
   
                sc = instance;
                if (sc == null) {
   
                    synchronized (SingletonDome03.class) {
   
                        if (sc == null) {
   
                            sc = new SingletonDome03();
                        }
                    }
                    instance=sc;
                }
            }
        }
        return instance;
    }
}

静态内部类实现方式(也是一种懒加载方式)

要点:

  • 外部类没有static属性,则不会像饿汉式那样立即加载对象。
  • 只有真正调用getInstance(),才会加载静态内部类。加载类时是线程 安全的。 instance是static final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性。
  • 兼备了并发高效调用和延迟加载的优势!
package com.ahzy;
/** * 静态类部类(也是一种懒加载) * @author 晓宇码匠 * 特点:延迟加载,调用效率高,线程安全 */
public class SingletonDome04 {
   
    private static class SingletClassInstance{
   
        private static SingletonDome04 instance = new SingletonDome04();
    }
    private SingletonDome04(){
     
    }
    public static SingletonDome04 getInstance(){
   
        return SingletClassInstance.instance;
    }
}

枚举实现单例模式

优点:

  • 实现简单.
  • 枚举本身就是单例模式。由JVM从根本上提供保障!避免通过反射和反序列化的漏洞!

缺点:无延迟加载.

package com.ahzy;
/** * 单例枚举式 * @author 晓宇码匠 * 优点:简单 * 缺点:没有延迟加载 */

public enum SingletonDome05 {
   
    //这个枚举元素,本身就是单例模式
    INSTANCE;
    //添加自己需要的操作
    public void singletonOperation() {
   
        
    }
}

测试

package com.ahzy;

public class Client {
   
    public static void main(String[] args) {
   
        SingletonDome01 s1 = SingletonDome01.getInstance(); 
        SingletonDome01 s2 = SingletonDome01.getInstance(); 
        
        System.out.println(s1);
        System.out.println(s2);
        
        System.out.println(SingletonDome05.INSTANCE==SingletonDome05.INSTANCE);
    }
}

结果:

com.ahzy.SingletonDome01@15db9742
com.ahzy.SingletonDome01@15db9742
true

破解单例

方法:反射和反序列化(不包含枚举式)
预防操作(这个一般会在开发jdk或一些jar包的时候会去用):

  • 反射可以破解上面几种(不包含枚举式)实现方式!(可以在构造方法中手动抛出异常控制)
  • 可以通过定义readResolve()防止获得不同对象。
  • 反序列化时,如果对象所在类定义了readResolve(),(实际是一种回调),定义返回哪个对象。
public class SingletonDemo01 implements Serializable {
   
    private static SingletonDemo01 s;

    private SingletonDemo01() throws Exception {
   
        if (s != null) {
   
            throw new Exception("只能创建一个对象");
            // 通过手动抛出异常,避免通过反射创建多个单例对象!
        }
    } // 私有化构造器

    public static synchronized SingletonDemo01 getInstance() throws Exception {
   
        if (s == null) {
   
            s = new SingletonDemo01();
        }
        return s;
    }

    // 反序列化时,如果对象所在类定义了readResolve(),(实际是一种回调),定义返回哪个对象。
    private Object readResolve() throws ObjectStreamException {
   
        return s;
    }
}

总结

  • 效率
模式 时间
饿汉式 22ms
静态内部类式 28ms
枚举式 32ms
双重检查锁式 65ms
懒汉式 636ms
  • 比较与特点
    主要:
    • 饿汉式(线程安全,调用效率高。 但是,不能延时加载。)
    • 懒汉式(线程安全,调用效率不高。 但是,可以延时加载。)
    其他:
    • 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用)
    • 静态内部类式(线程安全,调用效率高。 但是,可以延时加载)
    • 枚举式(线程安全,调用效率高,不能延时加载。并且可以天然的防止反射和反序列化漏洞!)
  • 如何选用?
    单例对象 占用 资源 少,不需要 延时加载:枚举式 好于 饿汉式。
    单例对象 占用 资源 大,需要 延时加载: 静态内部类式 好于 懒汉式。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

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

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

(0)


相关推荐

  • 大学学姐给学弟学妹们的寄语_怎么去大厂工作

    大学学姐给学弟学妹们的寄语_怎么去大厂工作很多小伙伴问我进大厂到底需要怎样的技术能力,经过几天的思考和总结,终于梳理出一份相对比较完整的技能清单,太顶了,建议收藏!!

  • MATLAB 粒子群算法,例题与常用模版

    MATLAB 粒子群算法,例题与常用模版MATLAB粒子群算法本文学习自:ParticleSwarmOptimizationinMATLAB-YarpizVideoTutorial与《精通MATLAB智能算法》1.简介:ParticleSwarmOptimization,粒子群优化算法,常用来找到方程的最优解。2.算法概述:每次搜寻都会根据自身经验(自身历史搜寻的最优地点)和种群…

  • HorizontalScrollView扩展总结

    HorizontalScrollView扩展总结ScrollView相信大家都已经比较熟悉了,它是支持垂直滚动的,在开发中经常使用到,与垂直滚动相对的就是水平滚动HorizontalScrollView,有时我们在进行页面切换的时候也会用到HorizontalScrollView。通过查看源码比较发现ScrollView和HorizontalScrollView有好多相同的方法。在说扩展之前,我先说一下HorizontalScrollVie

  • linux rsyslogd cpu占用率高问题「建议收藏」

    linux rsyslogd cpu占用率高问题「建议收藏」最近有几次,linuxcentos7服务停了后,重启,再起一些应用后,查看top后,rsyslogdcpu占用率高问题,先说我这块怀疑导致的原因吧。原因很有可能是当前机器的系统盘挂载出现问题,或者系统盘有磁道坏了,导致,在启动某个软件时,一直在记录日志。现象top命令看下一:解决发现rsyslog可以理解为增强版的syslog,可以支持输出日志到各种数据库,使用RELP+TCP实现数据的传输,对目前的服务器服务而言,可以关闭该进程。#第一步:重启rsyslog服务,

  • html浮雕效果代码_css内嵌式代码

    html浮雕效果代码_css内嵌式代码前言最近在看百度地图看到了一个效果,感觉这个效果用在网页上应该蛮赞的,于是就学习了一下。效果图如下:浮雕效果需要用到伸缩盒的知识(flex)flex在chrome是完全支持的,要加-webkit-前缀,其他的浏览器有的支持有的不支持,自己去查css手册,今天主要想讲一下怎么制作出浮雕效果先附上代码:<divclass=”title”>&…

  • Python画图源码|玫瑰花|皮卡丘|小猪佩奇|哆啦A梦|大白|小猫

    Python画图源码|玫瑰花|皮卡丘|小猪佩奇|哆啦A梦|大白|小猫Python各种画图源码Python各种画图源码Python真的太强大了,最近被Python的画图功能给震撼到了,原来Python还能这样画画,简直打开眼界。turtle没错,Python画图用的就是turtle这个库,这个库非常强大,简直就是神笔马良啊,可以画出各种你想要画的东西。所以下面一起来看一些效果图和视频吧效果图两个小孩皮卡丘小猪佩奇小熊猫小狗大熊小猫小鱼儿哆啦A梦小鸭子大白皮卡丘小

发表回复

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

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