博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JAVA设计模式 单例模式
阅读量:5808 次
发布时间:2019-06-18

本文共 2435 字,大约阅读时间需要 8 分钟。

定义

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

使用场景

确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且一个,例如,创建一个对象需要消耗资源过多,如访问IO和数据库等资源,这时就要考虑单例模式

1 饿汉式单例模式

public class DanLiDemo {    //饿汉单例模式    private static DanLiDemo sDanLiDemo = new DanLiDemo();    private DanLiDemo() {    }    public static DanLiDemo getInstance() {        return sDanLiDemo;    }}123456789101112131415复制代码

从上述代码中看出,类不能通过new的方式构造对象,只能通过getInstance来获取,这个sDanLiDemo 是静态的并且他是随类的加载而初始化的,这就保证了对象的唯一性,这个实现的核心在于构造方法的私有化,使得外部不能通过构造函数来构造对象,而通过一个静态方法返回一个对象

sDanLiDemo 是随着类的加载而初始化的,那么类什么时候加载?

类什么时候加载

类的加载是通过类加载器(Classloader)完成的,它既可以是饿汉式[eagerly load](只要有其它类引用了它就加载)加载类,也可以是懒加载[lazy load](等到类初始化发生的时候才加载)。不过我相信这跟不同的JVM实现有关,然而他又是受JLS保证的(当有静态初始化需求的时候才被加载)。

类什么时候初始化

加载完类后,类的初始化就会发生,意味着它会初始化所有类静态成员,以下情况一个类被初始化:

1实例通过使用new()关键字创建或者使用class.forName()反射,但它有可能导致ClassNotFoundException。

2类的静态方法被调用
3类的静态域被赋值
4静态域被访问,而且它不是常量
5在顶层类中执行assert语句

2 懒汉式单例模式

public class DanLiDemo {    private static DanLiDemo sDanLiDemo1;    private DanLiDemo() {    }    //懒汉单例模式    public static synchronized DanLiDemo getInstances() {        if (sDanLiDemo1 == null) {            sDanLiDemo1 = new DanLiDemo();        }        return sDanLiDemo1;    }}1234567891011121314151617复制代码

懒汉式是声明一个静态对象,并且在用户第一次调用getInstance时进行初始化,在getInstance加了synchronized 关键字,也就是说这是一个同步方法,这就是多线程情况下保证单例模式的手段,这个也是有问题的,即使已经被初始化,每次调用getInstance还会进行同步,这样会消耗不必要的资源,这也是懒汉模式的最大问题

Double Check Lock (DCL)实现单例

public class DanLiDemo {    private static DanLiDemo sDanLiDemo2 = null;    private DanLiDemo() {    }    //DCL实现单例    public static DanLiDemo gettInstance1() {        if (sDanLiDemo2 == null) {            synchronized (DanLiDemo.class) {                if (sDanLiDemo2 == null) {                    sDanLiDemo2 = new DanLiDemo();                }            }        }        return sDanLiDemo2;    }}12345678910111213141516171819202122复制代码

静态单例模式

DCL虽然在一定程度上解决了资源消耗,多余的同步,线程安全问题,但是,他还是某种情况下出现失效问题,这个问题被称为双重检查锁定(DCL失效)在《Java并发编程实践》一书谈到这个问题不赞成是使用,而建议如下下代码替代

public class DanLiDemo {    private DanLiDemo() {    }    //静态内部单例模式    public static DanLiDemo getInstance2() {        return DanLiDemoViewHolder.danli;    }    private static class DanLiDemoViewHolder {        private static final DanLiDemo danli = new DanLiDemo();    }}1234567891011121314151617复制代码

当第一次加载DanLiDemo时并不会初始化danli ,只有第一次调用DanLiDemo的getInstance方法才会导致danli的初始化,第一次调用getInstance方法会导致虚拟机加载DanLiDemoViewHolder类,这种方式不仅能够确保线程安全,也能办理对象的唯一性,同时也延迟了单例的实例化,所以推荐使用这种单例模式

转载地址:http://ulybx.baihongyu.com/

你可能感兴趣的文章
updatepanel中的GridView中的radiobuttonList怎么设置样式
查看>>
快速学习javaSE基础4---面向对象的编程
查看>>
关于Android四大组件的学习总结
查看>>
LeetCode 398: Random Pick Index
查看>>
uva live 7638 Number of Connected Components (并查集)
查看>>
Linux下设置svn开机自启动
查看>>
java只能的round,ceil,floor方法的使用
查看>>
雷公藤多甙治疗类风湿关节炎遭质疑
查看>>
Web前端开发学习误区,你掉进去了没?
查看>>
由于无法创建应用程序域,因此未能执行请求。错误: 0x80070002 系统找不到指定的文件...
查看>>
新开的博客,为自己祝贺一下
查看>>
numpy模块资源
查看>>
puppet任务计划
查看>>
nw打包
查看>>
【CQOI2011】放棋子
查看>>
一起来读多视图几何
查看>>
作用域声明提升
查看>>
采用JXL包进行EXCEL数据写入操作
查看>>
***CodeIgniter框架集成支付宝即时到账支付SDK
查看>>
Struts2访问ServletAPI的三种方式
查看>>