当前位置: 首页 > news >正文

java中你确定用对单例了吗?

作为程序员这样的特殊物种来说,都掌握了一种特殊能力就是编程思想,逻辑比較慎重,可是有时候总会忽略到一些细节,比方我,一直以来总认为Singleton是设计模式里最简单的,不用太在意,然而就是由于这样的不在意在开发中吃亏了.真的too young to simple.
好不扯淡了,直入主题.

在代码的世界里发现有各种写法的单例,有人说单例有5种,6种,7种…
对于单例的分类这点必须规范下,首先这么多种的分类是依据什么来定义的,基准是什么?

否则怎么会有那么多写法.

因此归纳下来,从延迟载入运行效率的角度出发主要也就分为两种,饿汉顾名思义就是运行效率高,但缺乏延时载入,其它写法差点儿相同都是懒汉式的一个拓展,或者优化而演化出来的,以下请看代码.

开发中经常使用的单例-饿汉式

public class SingletonDemo1 {

    private static final SingletonDemo1 s1 = new SingletonDemo1();

    public static SingletonDemo1 getInstance() {
        return s1;
    }

    private SingletonDemo1() {
    }
}

没错上面这块代码叫做单例-饿汉式,饿汉式一直以效率高而闻名于单例界,因此咋们开发中经常使用的单例模式也会选择他,简单而好用.
>

开发评价: ★★★★☆
延时载入: ★☆☆☆☆
运行效率: ★★★★★

耗时的蜗牛-懒汉式

public class SingletonDemo2 {
    private static SingletonDemo2 s1;

    public static synchronized SingletonDemo2 getInstance() {
        if (s1 == null) {
            s1 = new SingletonDemo2();
        }
        return s1;
    }

    private SingletonDemo2() {
    }
}

hello world这个世界里都知道这样的单例基本不会去用,在

double check双重检查锁-懒汉式

这能够说是上面饿汉式的一个缩影,为什么这么说,由于他并不完美,仍然有bug.

public class SingletonDemo3 {
    private static SingletonDemo3 s1;

    public static SingletonDemo3 getInstance() {
        if (s1 == null) {
        //这里使用了暂时变量
            SingletonDemo3 instance;
            synchronized (SingletonDemo3.class) {
                instance = s1;
                if (instance == null) {
                    synchronized (SingletonDemo3.class) {
                        if (instance == null) {
                            instance = new SingletonDemo3();
                        }
                    }
                    s1 = instance;
                }
            }
        }
        return s1;
    }
}

这个方式主要是通过if推断非null实例,提高了运行的效率,不必每次getInstace都要进行synchronize,仅仅要第一次要同步,有没创建了不用.

可是为什么说这样的写法有bug?这个问题主要是java的jvm层内部模型引起的.简单点说就是instance引用的对象有可能还没有完毕初始化完就直接返回该实例过去,在jdk1.5后这个问题才得到了优化,这不多说,能够看看这篇博文讲得不错.
详情见

当然也有了一些解决方法

  • 使用volatile关键字解决双重检查锁定的bug,对于volatile关键字就是Java中提供的另一种解决可见性和有序性问题的方案.
public class SafeDoubleCheckedLocking {
//加入了volatile关键字
    private volatile static Instance instance;

    public static Instance getInstance() {
        if (instance == null) {
            synchronized (SafeDoubleCheckedLocking.class) {
                if (instance == null)
                    instance = new Instance();//instance为volatile。如今没问题了
            }
        }
        return instance;
    }
}

>

开发评价: ★★★☆☆
延时载入: ★★★☆☆
运行效率: ★★★☆☆

推荐使用的静态内部类-懒汉式

public class SingletonDemo4 {

    //通过静态内部类的方式来实例化对象
    private static class InnerSingleton {
        private static final SingletonDemo4 instance = new SingletonDemo4();
    }

    public static  SingletonDemo4 getInstance() {
        return InnerSingleton.instance;
    }

    private SingletonDemo4() {
    }
}

这周方式是利用了类载入的一些特性,在classloder的机制中,初始化instance时仅仅有一个线程,并且这样的方式另一个优点就是起到了延时载入的效果,当SingletonDemo4被载入了,可是内部类InnerSingleton并不会被载入,由于InnerSingleton没有主动使用,仅仅有通过调用getInstance方法时才会去载入InnerSingleton类,进而实例private static final SingletonDemo4 instance = new SingletonDemo4();
因此这样的巧妙的方式比起双重检查锁来说,安全来又高效了些.
>

开发评价: ★★★★☆
延时载入: ★★★★☆
运行效率: ★★★★☆

推荐使用的枚举-饿汉式

public enum SingletonDemo5 {

    //枚举元素本身就是一个单例(名字能够任意定义);
    INSTANCE;

    //能够做一些单例的初始化操作
    public void singletonOperation() {
    }
}

这样的方式事实上非常帅,可是在实际开发中非常少人使用过,这点有点奇怪,首先enum本身就是一个单例,并且枚举另一个特性,能够避免放序列化和反射破解单例问题,经理再也不用操心单例安全了,可能是1.5才有enum的原因吧,假设项目适合的话能够试下这样的单例.
>

开发评价: ★★★★☆
延时载入: ★★★★☆
运行效率: ★★★★☆

总结一下:

对于以下的单例总的来说各有各的优点,至于开发中使用哪个能够依据你的业务需求来选择.

  • 饿汉
    • 标准饿汉 (安全防护方面 枚举单例更优于标准饿汉)
      线程安全,高效,不能够懒载入
    • 枚举单例
      线程安全,高效,不能够懒载入(天然避免反射与反序列化)
  • 懒汉 (效率方面 静态内部类更优于标准懒汉)
    • 标准懒汉
      线程安全,低效,能够懒载入
    • 双重检測(不推荐,有bug)
      线程安全,低效,能够懒载入
    • 静态内部类
      线程安全,低效,能够懒载入

对于单例的安全性问题,能够继续你那帅气的阅读姿势, java中你的单例是不是一直在裸奔

转载于:https://www.cnblogs.com/yutingliuyl/p/7349600.html

相关文章:

  • 深入分析Sleep(0)与Sleep(1)的区别
  • swift3.0常用操作包含删除字符串(string),更换字符串,插入字符串
  • 第21章 RTX 低功耗之睡眠模式
  • Spring思维导图(AOP篇)
  • layer close 关闭层IE9-浏览器崩溃问题解决
  • Java-static
  • 克隆用户过狗提权
  • Linux中如何查看显卡硬件信息
  • 搭建本地yum源服务器
  • Linux下NMAP常用扫描简介(一)
  • 利用Sympy计算sin1°的最小多项式
  • sql server2008 在window2012 R2安装集群注意事项
  • IBM“绿色地平线”为中网加油 大数据技术助力全民健身
  • Android5.0之后的页面切换动画
  • .NET轻量级ORM组件Dapper葵花宝典
  • angular学习第一篇-----环境搭建
  • C++类的相互关联
  • HTML5新特性总结
  • JS实现简单的MVC模式开发小游戏
  • js写一个简单的选项卡
  • JWT究竟是什么呢?
  • magento2项目上线注意事项
  • MySQL几个简单SQL的优化
  • Python_网络编程
  • Rancher如何对接Ceph-RBD块存储
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • Swift 中的尾递归和蹦床
  • Vue UI框架库开发介绍
  • windows下mongoDB的环境配置
  • 技术胖1-4季视频复习— (看视频笔记)
  • 两列自适应布局方案整理
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 数据科学 第 3 章 11 字符串处理
  • 从如何停掉 Promise 链说起
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #DBA杂记1
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • #每日一题合集#牛客JZ23-JZ33
  • #微信小程序:微信小程序常见的配置传旨
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (solr系列:一)使用tomcat部署solr服务
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (转)树状数组
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .net core webapi 大文件上传到wwwroot文件夹
  • .Net Remoting常用部署结构
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .net下简单快捷的数值高低位切换
  • .Net语言中的StringBuilder:入门到精通
  • @AutoConfigurationPackage的使用
  • @zabbix数据库历史与趋势数据占用优化(mysql存储查询)
  • [CSS]CSS 的背景
  • [C语言][PTA基础C基础题目集] strtok 函数的理解与应用