博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
单例的五种实现方式,及其性能分析。
阅读量:5244 次
发布时间:2019-06-14

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

在23种设计模式中,单例是最简单的设计模式,但是也是很常用的设计模式。从单例的五种实现方式中我们可以看到程序员对性能的不懈追求。下面我将分析单例的五种实现方式的优缺点,并对其在多线程环境下的性能进行测试。

实现

单例模式适用于资源占用较多的类,保证一个类只有一个实例即单例。通用的做法就是构造器私有化,提供一个全局的访问点,返回类的实例。

uml图:

这里写图片描述

1.饿汉式

代码实现:

package com.zgh.gof23.singleton;

/**
* 饿汉式
* @author yuelin
*
*/
public class SingleDemo {
private static SingleDemo instance = new SingleDemo();
//私有化构造器
private SingleDemo() {
//防止其他通过反射调用构造方法,破解单例
if (instance != null) {
throw new RuntimeException();
}
}

//对外提供统一的访问点

public static SingleDemo getInstance() {
优点

1.实例的初始化由JVM装载类的时候进行,保证了线程的安全性

2.实现简单方便
3.实例的访问效率高
缺点

1.不能实现懒加载,如果不调用getInstance(),那么这个类就白白的占据内存,资源的利用率不高

注意

1.防止通过反射调用构造方法破解单例模式。

2.防止通过反序列产生新的对象。
2.懒汉式

代码实现:

package com.zgh.gof23.singleton;

/**

* 懒汉式实现单例
*
* @author zhuguohui
*
*/
public class SingleDemo2 {
// 此处并不初始化实例
private static SingleDemo2 instance;

private SingleDemo2() {

if (instance != null) {
throw new RuntimeException();
优点

1.只有使用这个类的时候才初始化实例,优化了资源利用率

缺点

1.为了实现线程安全,使用了同步方法获取,增加了访问的开销

注意

1.防止通过反射调用构造方法破解单例模式。

2.防止通过反序列产生新的对象。
3.双重检查

代码实现:

package com.zgh.gof23.singleton;

/**

* 双重检查
*
* @author www.vboyl130.cnzhuguohui
*
*/
public class SingleDemo3 {
private static SingleDemo3 instance;

private SingleDemo3() {

if (instance != null) {
throw new RuntimeException();
}
}

public static SingleDemo3 getInstance() {

//第一重检查,提高效率
if (instance == null) {
synchronized (SingleDemo3.class) {
//第二重检查保证线程安全
if (instance == null) {
instance = new SingleDemo3();
}
}
}
return instance;
优点

1.实现懒加载

2.通过缩小同步区域和第一次检查提高访问效率
缺点

1.为了实现线程安全,使用了同步方法获取,增加了访问的开销

注意

1.防止通过反射调用构造方法破解单例模式。

2.防止通过反序列产生新的对象。
4.静态内部类

代码实现:

/**

* 静态内部类实现单例
*
* @author zhuguohui
*
*/
public class SingleDemo4 {
private static SingleDemo4 instance;

private static class SingleDemo4Holder {

private static final SingleDemo4 instance = new SingleDemo4();
}

private SingleDemo4() {

if (instance != null) {
throw new www.xyseo.net/ RuntimeException();
}
}

/**

* 调用这个方法的时候,JVM才加载静态内部类,才初始化静态内部类的类变量。由于由JVM初始化,保证了线程安全性,
* 同时又实现了懒加载
* @return
*/
public static SingleDemo4 getInstance() {
return www.yuheng119.com/ SingleDemo www.ysylcsvip.cn 4Holder.instance;
优点

1.即实现了线程安全,又实现了懒加载

缺点

2.实现稍显复杂

5.枚举实现

代码实现:

/**

* 枚举实现单例
* 枚举由JVM实现其的单例性
* @author zhuguohui
*
*/
public enum SingleDemo5 {
INSTANCE;
优点

1.实现简单

2.线程安全
3.天热对反射和反序列化漏洞免疫(由JVM提供)
缺点

2.不能实现懒加载

注意

1.防止通过反射调用构造方法破解单例模式。

2.防止通过反序列产生新的对象。
测试

源码

public class APP {

public static void main(String[www.sb45475.com] args) {

int threadCount = 100;

long start = System.currentTimeMillis();
final CountLock lock = new CountLock(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(new Runnable() {

@Override

public void run() {
for (int j = 0; j < 10000000; j++) {
//通过更换此处,来测试不同单例实现方式在多线程环境下的性能
SingleDemo5 demo = SingleDemo5.INSTANCE;
}
lock.finish();
}
}).start();

}

//等待所有线程执行完
lock.waitForWrok();
long end = System.currentTimeMillis();
System.out.println("总共耗时" + (end - start));
}
为了统计所以线程执行完需要的时间,我写了一个工具类

package com.zgh.gof23.singleton;

public class CountLock {

//线程的总数量
private int count;

public CountLock(int www.dejiaylsmile.cn count) {

this.count = count;
}

/**

* 当一个线程完成任务以后,调用一次这个方法
*/
public synchronized www.jnd3658.cn void finish() {
count--;
if (count == 0) {
notifyAll();
}
}

/**

* 需要等待其他线程执行完的线程,调用此方法。
*/
public synchronized void waitForWrok() {
while (count > 0) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace(www.wmylzc.cn);
}
}
}

结果

五种单例实现方式,在100个线程下,每个线程访问1千万次实例的用时.

Tables 实现方式 用时(毫秒)

1 饿汉式 13
2 懒汉式 10778
3 双重检查 15
4 静态内部类 14
5 枚举 12
(*注意:由于不同电脑之间的性能差异,测试的结果可能不同)

总结

如果需要懒加载就使用静态内部类方式,如果不需要就使用枚举方式。

转载于:https://www.cnblogs.com/chenergougou/p/7115449.html

你可能感兴趣的文章
Java大数——a^b + b^a
查看>>
poj 3164 最小树形图(朱刘算法)
查看>>
服务器内存泄露 , 重启后恢复问题解决方案
查看>>
android一些细节问题
查看>>
KDESVN中commit时出现containing working copy admin area is missing错误提示
查看>>
利用AOP写2PC框架(二)
查看>>
【动态规划】skiing
查看>>
java定时器的使用(Timer)
查看>>
ef codefirst VS里修改数据表结构后更新到数据库
查看>>
boost 同步定时器
查看>>
[ROS] Chinese MOOC || Chapter-4.4 Action
查看>>
简单的数据库操作
查看>>
解决php -v查看到版本与phpinfo()版本不一致问题
查看>>
iOS-解决iOS8及以上设置applicationIconBadgeNumber报错的问题
查看>>
亡灵序曲-The Dawn
查看>>
Redmine
查看>>
帧的最小长度 CSMA/CD
查看>>
xib文件加载后设置frame无效问题
查看>>
编程算法 - 左旋转字符串 代码(C)
查看>>
IOS解析XML
查看>>