java 单例的五种实现方式及其性能分析

序言
在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.实例的初始化由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;
}
优点
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));
}
}
为了统计所以线程执行完需要的时间,我写了一个工具类
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千万次实例的用时.
| Tables | 实现方式 | 用时(毫秒) |
|---|---|---|
| 1 | 饿汉式 | 13 |
| 2 | 懒汉式 | 10778 |
| 3 | 双重检查 | 15 |
| 4 | 静态内部类 | 14 |
| 5 | 枚举 | 12 |
(*注意:由于不同电脑之间的性能差异,测试的结果可能不同)
总结
如果需要懒加载就使用静态内部类方式,如果不需要就使用枚举方式。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
# java
# 单例的五种实现方式
# 单例的5种方式对比
# JAVA设计模式零基础解析之单例模式的八种方式
# Java单例模式的6种实现方式详解
# 分析java中全面的单例模式多种实现方式
# JAVA破坏单例模式的方式以及避免方法
# 详解Java实现单例的五种方式
# Java单例模式实现的几种方式
# 详解Java中的八种单例创建方式
# 加载
# 五种
# 实现了
# 多线程
# 增加了
# 使用了
# 不需要
# 适用于
# 对其
# 希望能
# 不高
# 可以看到
# 较多
# 写了
# 我将
# 只有一个
# 谢谢大家
# 提供一个
# 最简单
# 完成任务
相关文章:
网站制作多少钱一个,建一个论坛网站大约需要多少钱?
大同网页,大同瑞慈医院官网?
天河区网站制作公司,广州天河区如何办理身份证?需要什么资料有预约的网站吗?
利用JavaScript实现拖拽改变元素大小
建站10G流量真的够用吗?如何应对访问高峰?
建站主机选购指南:核心配置与性价比推荐解析
开封网站制作公司,网络用语开封是什么意思?
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
如何在万网ECS上快速搭建专属网站?
如何选择美橙互联多站合一建站方案?
焦点电影公司作品,电影焦点结局是什么?
交易网站制作流程,我想开通一个网站,注册一个交易网址,需要那些手续?
建站之星后台管理如何实现高效配置?
c++怎么使用类型萃取type_traits_c++ 模板元编程类型判断【方法】
青岛网站建设如何选择本地服务器?
网站制作公司广州有几家,广州尚艺美发学校网站是多少?
建站ABC备案流程中有哪些关键注意事项?
品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?
常州自助建站:操作简便模板丰富,企业个人快速搭建网站
网站制作中优化长尾关键字挖掘的技巧,建一个视频网站需要多少钱?
如何基于云服务器快速搭建网站及云盘系统?
北京制作网站的公司排名,北京三快科技有限公司是做什么?北京三快科技?
建站之星后台搭建步骤解析:模板选择与产品管理实操指南
零基础网站服务器架设实战:轻量应用与域名解析配置指南
湖北网站制作公司有哪些,湖北清能集团官网?
如何通过WDCP绑定主域名及创建子域名站点?
C++如何将C风格字符串(char*)转换为std::string?(代码示例)
如何零基础开发自助建站系统?完整教程解析
上海网站制作开发公司,上海买房比较好的网站有哪些?
宝塔建站助手安装配置与建站模板使用全流程解析
如何破解联通资金短缺导致的基站建设难题?
惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?
独立制作一个网站多少钱,建立网站需要花多少钱?
C++中引用和指针有什么区别?(代码说明)
岳西云建站教程与模板下载_一站式快速建站系统操作指南
淘宝制作网站有哪些,淘宝网官网主页?
如何在Windows 2008云服务器安全搭建网站?
如何通过云梦建站系统实现SEO快速优化?
如何用PHP工具快速搭建高效网站?
建站主机核心功能解析:服务器选择与网站搭建流程指南
制作网页的网站有哪些,电脑上怎么做网页?
已有域名如何快速搭建专属网站?
建站之星在线客服如何快速接入解答?
XML的“混合内容”是什么 怎么用DTD或XSD定义
在线流程图制作网站手机版,谁能推荐几个好的CG原画资源网站么?
打鱼网站制作软件,波克捕鱼官方号怎么注册?
建站之星手机一键生成:多端自适应+小程序开发快速建站指南
制作充值网站的软件,做人力招聘为什么要自己交端口钱?
如何选择高性价比服务器搭建个人网站?
建站之星后台管理:高效配置与模板优化提升用户体验
*请认真填写需求信息,我们会在24小时内与您取得联系。