在java中,单例有很多种写法,面试时,手写代码环节,除了写算法题,有时候也会让手写单例模式,这里记录一下单例的几种写法和优缺点。

为什么使用单例

1、在内存中只有一个对象,节省内存空间。避免频繁的创建销毁对象,可以提高性能。避免对共享资源的多重占用。可以全局访问

2、确保一个类只有一个实例,自行实例化并向系统提供这个实例

单例需要注意的问题

1、线程安全问题

2、资源使用问题

实际上本文就是在讨论这两个问题。

1、饿汉式

package com;public class Singleton{    private static Singleton instance = new Singleton() ;    private Singleton(){    }    public static Singleton getInstance(){         return  instance ;     } }

优点:

在未调用getInstance() 之前,实例就已经创建了,天生线程安全。

缺点:

如果一直没有调用getInstance() , 但是已经创建了实例,造成了资源浪费。

2、懒汉式

package com;public class Person{    private static Person person ;    private Person(){    }    public static Person get(){        if ( person == null ) {            person = new Person() ;        }        return person ;    }}

优点:

get() 方法被调用的时候,才创建实例,节省资源。

缺点:

线程不安全。

这种模式,可以做到单例模式,但是只是在单线程中是单例的,如果在多线程中操作,可能出现多个实例。

package com;public class A1  {    public static void main(String[] args){        for ( int i = 0 ;  i

结果,可以看到出现了两个 Person 实例,效果图如下:

创建两个实例原因分析:

线程A希望使用 Person ,调用 get()方法。因为是第一次调用,A 就发现 person 是 null 的,于是它开始创建实例,就在这个时候,CPU 发生时间片切换,线程B开始执行,它要使用 Person ,调用get()方法,同样检测到 person 是null ——注意,这是在 A 检测完之后切换的,也就是说 A 并没有来得及创建对象——因此 B 开始创建。B创建完成后,切换到A继续执行,因为它已经检测完了,所以A不会再检测一遍,它会直接创建对象。这样,线程 A 和 B 各自拥有一个 Person 的对象——单例失败!

总结:

1、可以实现单线程单例

2、多线单例无法保证

改进:

加锁

3、synchronized 加锁同步

package com;public class Person{    private static Person person ;    private Person(){    }    public synchronized static Person get(){        if ( person == null ) {            person = new Person() ;        }        return person ;    }}

经过测试,已经可以满足多线程的安全问题了,synchronized 修饰的同步块可是要比一般的代码段慢上几倍的!如果存在很多次 get() 的调用,那性能问题就不得不考虑了!

优点:

1、满足单线程的单例

2、满足多线程的单例

缺点:

性能差

4、改进性能 双重校验

package com;public class Person{    private static Person person ;    private Person(){    }    public synchronized static Person get(){        if ( person == null ) {            synchronized ( Person.class ){                if (person == null) {                    person = new Person();                }            }        }        return person ;    }}

首先判断 person 是不是为 null ,如果为 null ,加锁初始化;如果不为 null ,直接返回 person 。整个设计,进行了双重校验。

优点:

1、满足单线程单例

2、满足多线程单例

3、性能问题得以优化

缺点:

第一次加载时反应不快,由于java内存模型一些原因偶尔失败

5、volatile 关键字,解决双重校验带来的弊端

package com;public class Person{    private static volatile Person person = null ;    private Person(){    }    public static Person getInstance(){        if ( person == null ) {            synchronized ( Person.class ){                if ( person == null ) {                    person = new Person() ;                }            }        }        return person ;    }}

假设没有关键字 volatile 的情况下,两个线程 A、B,都是第一次调用该单例方法,线程A先执行 person = new Person(),该构造方法是一个非原子操作,编译后生成多条字节码指令,由于JAVA的指令重排序,可能会先执行 person 的赋值操作,该操作实际只是在内存中开辟一片存储对象的区域后直接返回内存的引用,之后 person 便不为空了,但是实际的初始化操作却还没有执行,如果就在此时线程 B 进入,就会看到一个不为空的但是不完整 (没有完成初始化)的 Person 对象,所以需要加入 volatile 关键字,禁止指令重排序优化,从而安全的实现单例。

补充:看了图片加载框架 Glide (3.7.0版) 源码,发现 glide 也是使用 volatile 关键字的双重校验实现的单例,可见这种方法是值得信赖的。

6、静态内部类

package com;public class Person {    private Person(){    }    private static class PersonHolder{        /*** 静态初始化器,由JVM来保证线程安全*/        private static Person instance = new Person();    }    public static Person getInstance(){        return PersonHolder.instance;    }}

优点:

资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法

7、枚举类实现单例

package com;public enum Singleton {    INSTANCE ;    public void show(){        // Do you need to do things}}

使用

获取实例对象:Singleton.INSTANCE调用其他方法:Singleton.INSTANCE.show();

使用情景总结:

一、上面的7中方法,都实现了某种程度的单例,各有利弊,根据使用的场景不同,需要满足的特性不同,选取合适的单例方法才是正道。

二、对线程要求严格,对资源要求不严格的推荐使用:1 饿汉式

三、对线程要求不严格,对资源要求严格的推荐使用:2 懒汉式

四、对线程要求稍微严格,对资源要求严格的推荐使用:4 双重加锁

五、同时对线程、资源要求非常严格的推荐使用:5 、 6

点击图片了解详情

上海软件测试3期毕业10天,就业率达89.28%,平均薪资10736(点击图片)

什么时候投递简历成功率最高?这是一个细致活!(点击图片)

Chrome强大的15款插件,第11款程序员必备(点击图片)

卧底阿里、京东、美团,Java程序员为大家带回来的面试题(点击图片)

学姐QQ:2739250496

长按扫码可关注

学姐等你来撩

学姐微信:

CZBKSH

▼点击阅读原文加IT交流群

java单例弊端,博客大牛总结的Java单例写法的优缺点及使用场景相关推荐

  1. 各大公司java面试整理对应问题博客整理

    各大公司java面试整理对应问题博客整理! 阿里 分库分表 数据库中间件 MyCAT是一个强大的数据库中间件,不仅仅可以用作读写分离,以及分表分库.容灾管理,而且可以用于多租户应用开发.云平台基础设施 ...

  2. 2019年度CSDN博客之星TOP10榜单揭晓,你上榜了吗?

    培根说,『读书造成充实的人,会议造成未能觉悟的人,写作造成正确的人』. 在短信短视频快速迭代的快时代,更深度的思考.更正确的实践,更成体系的写作与分享,尤显可贵.这里,每一篇博文都是开发者实战的经验解 ...

  3. 2023计算机毕业设计SSM最新选题之java“逢遇”个人博客平台qaoxv

    2023计算机毕业设计SSM最新选题之java"逢遇"个人博客平台qaoxv 这个的话首先你对那些方面比较熟悉,毕竟软件工程范围还是比较广的,所以这个你得要自己确定好方向,这个很重 ...

  4. 2015-2016-2 《Java程序设计》 学生博客及Git@OSC 链接

    2015-2016-2 <Java程序设计> 学生博客及Git@OSC 链接 博客 1451 20145101王闰开 20145102周正一 20145103冯文华 20145104张家明 ...

  5. [转载]Word直接发布新浪博客(以Word 2013为例)

    2019独角兽企业重金招聘Python工程师标准>>> 原文地址:Word直接发布新浪博客(以Word 2013为例) 作者:paulke2011 注意:这篇博客直接由Word 20 ...

  6. 基于Java/Mysql的个人博客网站

    3年前写的一个技术博客...纪念一下. OpenIdea Blog - 开源灵感博客 a personal blog site based on Java/Mysql - 基于Java/Mysql的个 ...

  7. JAVA课程设计个人博客 学生成绩管理 201521123014 黄绍桦

    JAVA课程设计个人博客 学生成绩管理 201521123014 黄绍桦 1. 团队课程设计博客链接 http://www.cnblogs.com/kawajiang/p/7062407.html 2 ...

  8. 基于JAVA基于网络平台个人博客系统计算机毕业设计源码+系统+lw文档+部署

    基于JAVA基于网络平台个人博客系统计算机毕业设计源码+系统+lw文档+部署 基于JAVA基于网络平台个人博客系统计算机毕业设计源码+系统+lw文档+部署 本源码技术栈: 项目架构:B/S架构 开发语 ...

  9. 数风流人物,俱在今朝!|2019年度CSDN博客之星TOP10榜单揭晓-智华非常荣幸入选中国博客之星TOP9,非常感谢大家的支持,愿和读者朋友们共同努力,坚持学习,让每个人都能实现自己的梦想!

    培根说,『读书造成充实的人,会议造成未能觉悟的人,写作造成正确的人』. 在短信短视频快速迭代的快时代,更深度的思考.更正确的实践,更成体系的写作与分享,尤显可贵.这里,每一篇博文都是开发者实战的经验解 ...

最新文章

  1. 《对软件工程课程的期望》
  2. 【OfficeDIY】有了站点了 ^_^
  3. 基于网络音频的Android播放程序简单示例
  4. java keytool 代码_JDK keytool证书工具功能代码解析_java_脚本之家
  5. 编写Dockerfile增强centos镜像:安装vim 和net-tools
  6. android list contain的使用
  7. jzoj5057-[GDSOI2017模拟4.13]炮塔【网络流,最大权闭合图】
  8. Qt学习笔记-QSqlModel的事物操作
  9. 三年级开始学计算机,三年级学生初识计算机的教学心得
  10. LeetCode : Word Pattern
  11. WSDM2022 | 数据困境: 我们究竟有多了解推荐系统数据集?(附视频、论文及代码)...
  12. Django视图系统
  13. 拓端tecdat|R语言回归中的Hosmer-Lemeshow拟合优度检验
  14. 2021算法竞赛入门班第一节课枚举贪心习题
  15. 读《高手》有感(包括问题、质疑、专业名词、哲理句)
  16. android翻书效果实现原理( 贝塞尔曲线绘制原理/点坐标计算)
  17. 信息化故事--温州的传奇(11)从“进城务工”看“温州新版自闭症”
  18. 光猫、交换机、路由器三者的区别在哪里?如何选择?
  19. ComicEnhancerPro 系列教程十八:JPG文件长度与质量
  20. 年入800万!韩国第一虚拟网红的崛起

热门文章

  1. creator小功能----关于帧动画Animation和骨骼动画Skeleton一些有趣的东西
  2. 写给小白的Python之016:面向对象-魔法方法
  3. Electronics Enthusiastic
  4. nginx 动态设置黑名单
  5. 美国服务器减少延迟,美国服务器延迟的原因及解决办法
  6. 浏览器缓存(强缓存和协商缓存)
  7. 如何有效利用大数据?
  8. ECDSA host key for ... has changed and you have requested strict checking.Host key verification fail
  9. CSDN中空格的常用输入方法
  10. 计算机maple3D绘图画爱心,【1人回答】用3DMax做个爱心的形状怎么做?-3D溜溜网...