单例的五种实现方式,及其性能分析。
来源:互联网 发布:labview串口数据采集 编辑:程序博客网 时间:2024/05/16 12:23
序言
在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() { return instance; }}
- 1
优点
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(); } } /** * 当调用此方法的时候才初始化实例, 为了实现线程安全,需要使用同步方法 * * @return */ public static synchronized SingleDemo2 getInstance() { if (instance == null) { instance = new SingleDemo2(); } return instance; }}
优点
1.只有使用这个类的时候才初始化实例,优化了资源利用率
缺点
1.为了实现线程安全,使用了同步方法获取,增加了访问的开销
注意
1.防止通过反射调用构造方法破解单例模式。2.防止通过反序列产生新的对象。
3.双重检查
代码实现:
package com.zgh.gof23.singleton;/** * 双重检查 * * @author zhuguohui * */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 RuntimeException(); } } /** * 调用这个方法的时候,JVM才加载静态内部类,才初始化静态内部类的类变量。由于由JVM初始化,保证了线程安全性, * 同时又实现了懒加载 * @return */ public static SingleDemo4 getInstance() { return SingleDemo4Holder.instance; }}
优点
1.即实现了线程安全,又实现了懒加载
缺点
2.实现稍显复杂
5.枚举实现
代码实现:
/** * 枚举实现单例 * 枚举由JVM实现其的单例性 * @author zhuguohui * */public enum SingleDemo5 { INSTANCE;
- 9
优点
1.实现简单2.线程安全3.天热对反射和反序列化漏洞免疫(由JVM提供)
缺点
2.不能实现懒加载
注意
1.防止通过反射调用构造方法破解单例模式。2.防止通过反序列产生新的对象。
测试
源码
public class APP { public static void main(String[] 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)); }}
- 1
- 2
- 3
为了统计所以线程执行完需要的时间,我写了一个工具类
package com.zgh.gof23.singleton;public class CountLock { //线程的总数量 private int count; public CountLock(int count) { this.count = count; } /** * 当一个线程完成任务以后,调用一次这个方法 */ public synchronized 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(); } } }}
结果
五种单例实现方式,在100个线程下,每个线程访问1千万次实例的用时.
(*注意:由于不同电脑之间的性能差异,测试的结果可能不同)
总结
如果需要懒加载就使用静态内部类方式,如果不需要就使用枚举方式。
阅读全文
0 0
- 单例的五种实现方式,及其性能分析。
- 单例的五种实现方式,及其性能分析。
- 单例的五种实现方式,及其性能分析
- 单例的五种实现方式,及其性能分析(转)
- 单例模式的五种实现方式
- 单例模式的五种实现方式
- 单例模式的五种实现方式
- 单例模式五种实现方式
- 五种创建单例的方式
- 单例模式的7种实现方式及分析
- 单例模式 及其实现方式
- java单例模式五种实现方式
- ANDROID设计模式之单例模式的五种实现方式
- JAVA设计模式-单例模式(Singleton)的五种实现方式
- HashMap循环遍历方式及其性能对比 主要介绍HashMap的四种循环遍历方式,各种方式的性能测试对比,根据HashMap的源码实现分析性能结果,总结结论。
- Java多线程(五)之BlockingQueue深入分析及其实现类实现方式分析
- 单例模式详细分析&7种实现方式
- 单例的三种实现方式
- 复制
- java中的内存
- 二重积分
- js显示当前日期及定时器
- HTML基础2
- 单例的五种实现方式,及其性能分析。
- centos安装 源码包nginx步骤 ,nginx工作原理 nginx优点
- bzoj 2007: [Noi2010]海拔(最短路)
- 练习笔记:linux常见命令
- BZOJ 2190 仪仗队(欧拉函数)
- 【BZOJ2190】【数学】仪仗队 题解
- C++构造函数和析构函数中抛出异常的注意事项
- API-StringBuffer与StringBuilder
- 数据库索引