- 浏览: 7325677 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (1546)
- 企业中间件 (236)
- 企业应用面临的问题 (236)
- 小布Oracle学习笔记汇总 (36)
- Spring 开发应用 (54)
- IBatis开发应用 (16)
- Oracle基础学习 (23)
- struts2.0 (41)
- JVM&ClassLoader&GC (16)
- JQuery的开发应用 (17)
- WebService的开发应用 (21)
- Java&Socket (44)
- 开源组件的应用 (254)
- 常用Javascript的开发应用 (28)
- J2EE开发技术指南 (163)
- EJB3开发应用 (11)
- GIS&Mobile&MAP (36)
- SWT-GEF-RCP (52)
- 算法&数据结构 (6)
- Apache开源组件研究 (62)
- Hibernate 学习应用 (57)
- java并发编程 (59)
- MySQL&Mongodb&MS/SQL (15)
- Oracle数据库实验室 (55)
- 搜索引擎的开发应用 (34)
- 软件工程师笔试经典 (14)
- 其他杂项 (10)
- AndroidPn& MQTT&C2DM&推技术 (29)
- ActiveMQ学习和研究 (38)
- Google技术应用开发和API分析 (11)
- flex的学习总结 (59)
- 项目中一点总结 (20)
- java疑惑 java面向对象编程 (28)
- Android 开发学习 (133)
- linux和UNIX的总结 (37)
- Titanium学习总结 (20)
- JQueryMobile学习总结 (34)
- Phonegap学习总结 (32)
- HTML5学习总结 (41)
- JeeCMS研究和理解分析 (9)
最新评论
-
lgh1992314:
[u][i][b][flash=200,200][url][i ...
看看mybatis 源代码 -
尼古拉斯.fwp:
图片根本就不出来好吧。。。。。。
Android文件图片上传的详细讲解(一)HTTP multipart/form-data 上传报文格式实现手机端上传 -
ln94223:
第一个应该用排它网关吧 怎么是并行网关, 并行网关是所有exe ...
工作流Activiti的学习总结(八)Activiti自动执行的应用 -
ZY199266:
获取不到任何消息信息,请问这是什么原因呢?
ActiveMQ 通过JMX监控Connection,Queue,Topic的信息 -
xiaoyao霄:
DestinationSourceMonitor 报错 应该导 ...
ActiveMQ 通过JMX监控Connection,Queue,Topic的信息
本文将探讨单例模式的各种情况,并给出相应的建议。 单例模式应该是设计模式中比较简单的一个,但是在多线程并发的环境下使用却是不那么简单了。
首先看最原始的单例模式。
2
3 public class Singleton {
4
5 private static Singleton instance = null;
6
7 private Singleton() {
8 }
9
10 public static Singleton getInstance() {
11 if (instance == null) {
12 instance = new Singleton();
13 }
14 return instance;
15 }
16 }
17
显然这个写法在单线程环境下非常好,但是多线程会导致多个实例出现,这个大家都能理解。
最简单的改造方式是添加一个同步锁。
2
3 public class SynchronizedSingleton {
4
5 private static SynchronizedSingleton instance = null;
6
7 private SynchronizedSingleton() {
8 }
9
10 public static synchronized SynchronizedSingleton getInstance() {
11 if (instance == null) {
12 instance = new SynchronizedSingleton();
13 }
14 return instance;
15 }
16 }
17
显然上面的方法避免了并发的问题,但是由于我们只是在第一次构造对象的时候才需要同步,以后就不再需要同步,所以这里不可避免的有性能开销。于是将锁去掉采用静态的属性来解决同步锁的问题。
2
3 public class StaticSingleton {
4
5 private static StaticSingleton instance = new StaticSingleton();
6
7 private StaticSingleton() {
8 }
9
10 public static StaticSingleton getInstance() {
11 return instance;
12 }
13 }
14
上面的方法既没有锁又解决了性能问题,看起来已经满足需求了。但是追求“完美”的程序员想延时加载对象,希望在第一次获取的时候才构造对象,于是大家非常聪明的进行改造,也即非常出名的双重检查锁机制出来了。
2
3 public class DoubleLockSingleton {
4
5 private static DoubleLockSingleton instance = null;
6
7 private DoubleLockSingleton() {
8 }
9
10 public static DoubleLockSingleton getInstance() {
11 if (instance == null) {
12 synchronized (DoubleLockSingleton.class) {
13 if (instance == null) {
14 instance = new DoubleLockSingleton();
15 }
16 }
17 }
18 return instance;
19 }
20 }
21
双重锁机制看起来非常巧妙的避免了上面的问题。但是真的是这样的吗?文章《双重检查锁定及单例模式》中谈到了非常多演变的双重检查锁机制带来的问题,包括比较难以理解的指令重排序机制等。总之就是双重锁机制仍然对导致错误问题而不是性能问题。
于是继续改造,某个牛人利用JVM的特性来解决上述问题,具体哪个牛人我忘记了,但是不是下面文章的作者。
(1)《Java theory and practice: Fixing the Java Memory Model, Part 2》
(2)《Initialize-On-Demand Holder Class and Singletons》
2
3 public class HolderSingleton {
4
5 private static class HolderSingletonHolder {
6
7 static HolderSingleton instance = new HolderSingleton();
8 }
9
10 private HolderSingleton() {
11 //maybe throw an Exception when doing something
12 }
13
14 public static HolderSingleton getInstance() {
15 return HolderSingletonHolder.instance;
16 }
17 }
18
上述代码看起来解决了上面单例模式遇到的所有问题,而且实际上工作的很好,没有什么问题。但是却有一个致命的问题,如果第11行抛出了一个异常,也就是第一次构造函数失败将导致永远无法再次得到构建对象的机会。
使用下面的代码测试下。
2
3 public class HolderSingletonTest {
4
5 private static class HolderSingletonHolder {
6
7 static HolderSingletonTest instance = new HolderSingletonTest();
8 }
9
10 private static boolean init = false;
11
12 private HolderSingletonTest() {
13 //maybe throw an Exception when doing something
14 if(!init) {
15 init=true;
16 throw new RuntimeException(“fail“);
17 }
18 }
19
20 public static HolderSingletonTest getInstance() {
21 return HolderSingletonHolder.instance;
22 }
23 public static void main(String[] args) {
24 for(int i=0;i<3;i++) {
25 try {
26 System.out.println(HolderSingletonTest.getInstance());
27 } catch (Exception e) {
28 System.err.println(“one->“+i);
29 e.printStackTrace();
30 }catch(ExceptionInInitializerError err) {
31 System.err.println(“two->“+i);
32 err.printStackTrace();
33 }catch(Throwable t) {
34 System.err.println(“three->“+i);
35 t.printStackTrace();
36 }
37 }
38 }
39 }
40
很不幸将得到以下输出:
two->0
java.lang.ExceptionInInitializerError
at xylz.study.singleton.HolderSingletonTest.getInstance(HolderSingletonTest.java:21)
at xylz.study.singleton.HolderSingletonTest.main(HolderSingletonTest.java:26)
Caused by: java.lang.RuntimeException: fail
at xylz.study.singleton.HolderSingletonTest.<init>(HolderSingletonTest.java:16)
at xylz.study.singleton.HolderSingletonTest.<init>(HolderSingletonTest.java:12)
at xylz.study.singleton.HolderSingletonTest$HolderSingletonHolder.<clinit>(HolderSingletonTest.java:7)
… 2 more
three->1
java.lang.NoClassDefFoundError: Could not initialize class xylz.study.singleton.HolderSingletonTest$HolderSingletonHolder
at xylz.study.singleton.HolderSingletonTest.getInstance(HolderSingletonTest.java:21)
at xylz.study.singleton.HolderSingletonTest.main(HolderSingletonTest.java:26)
three->2
java.lang.NoClassDefFoundError: Could not initialize class xylz.study.singleton.HolderSingletonTest$HolderSingletonHolder
at xylz.study.singleton.HolderSingletonTest.getInstance(HolderSingletonTest.java:21)
at xylz.study.singleton.HolderSingletonTest.main(HolderSingletonTest.java:26)
很显然我们想着第一次加载失败第二次能够加载成功,非常不幸,JVM一旦加载某个类失败将认为此类的定义有问题,将来不再加载,这样就导致我们没有机会再 加载。目前看起来没有办法避免此问题。如果要使用JVM的类加载特性就必须保证类加载一定正确,否则此问题将比并发和性能更严重。如果我们的类需要初始话 那么就需要想其它办法避免在构造函数中完成。看起来像是又回到了老地方,难道不是么?
总之,结论是目前没有一个十全十美的单例模式,而大多数情况下我们只需要满足我们的需求就行,没必有特意追求最“完美”解决方案。
发表评论
-
Mule ESB 学习笔记(20)Mule和Spring httpinvoker的整合
2013-08-28 13:59 3741mule的配置文件: <?xml version=& ... -
Mule ESB 学习笔记(19)Mule和RSS的整合
2013-08-28 10:08 2576定时扫描特定目录的rss文件: <?xml vers ... -
Mule ESB 学习笔记(18)Mule和ATOM的整合
2013-08-27 20:00 2590定时读取特定文件的rss文件: <?xml ... -
Mule ESB 学习笔记(17)Mule和JMX的整合
2013-08-27 16:48 4040Agent的实现: package com.easyway ... -
Mule ESB 学习笔记(16)CXF SOAP基于SAML的验证的配置
2013-08-27 15:19 3780mule的配置 <mule xmlns:core=& ... -
Mule ESB 学习笔记(15)CXF SOAP基于JKS的验证的配置
2013-08-27 14:57 3853mule的配置如下: <mule xmlns:cor ... -
Mule ESB 学习笔记(14)CXF SOAP基于UsernameToken的验证
2013-08-27 14:16 7934简单需求: 针对在webservice ... -
Mule ESB 学习笔记(13)CSV数据文件到数据库
2013-08-26 17:54 7021简单需求: ... -
Mule ESB 学习笔记(12)JSON转换器的使用
2013-08-26 13:54 9065在许多情况下,可能需要把类转换为js ... -
Mule ESB 学习笔记(11)Web Service Proxy
2013-08-24 19:32 6606一、WebSevice Proxy 简介 ... -
Mule ESB 学习笔记(10)mule事务配置
2013-08-23 16:36 6214在mule的事务可能为jdbc事务,jms事务 ... -
Mule ESB 学习笔记(9)mule配置常用节点解释
2013-08-23 13:27 34121 Mule-config.x ... -
Mule ESB 学习笔记(8)mule和jersey的整合使用
2013-08-23 11:20 3925在项目常用jesery作为rest ... -
Mule ESB 学习笔记(7)服务调用
2013-08-23 10:44 18886一. 服务调用 1. Mule实现并提供Web Servi ... -
Mule ESB 学习笔记(6)配置模式
2013-08-23 10:42 4752为了节省时间,就不翻译了,摘抄重点总结 ... -
Mule ESB 学习笔记(5)异步请求-响应方式
2013-08-22 15:32 35665.4 异步请求-响应方式 异步请求-响应方式即请求方调用 ... -
Mule ESB 学习笔记(4)同步方式
2013-08-22 15:19 42235.3 同步方式 同步方式即请求方调用 ... -
JBOSS EJB3项目启动执行一个任务
2013-08-06 22:26 3811在jboss的项目中,jboss启动 ... -
Jboss @Service的使用
2013-08-06 21:59 1971Jboss有一个扩展的annotation——@Servic ... -
julian Date 计算 和实现
2013-08-01 09:32 4422Qt库里CBSDate类的内部实现用_jd成员进行计算、比较 ...
相关推荐
本文将重点介绍C#中两种不同的单例模式实现方法:基于嵌套类的完全懒惰加载和使用.NET 4.0的`Lazy<T>`类型。 #### 二、基于嵌套类的完全懒惰加载 ##### 2.1 实现原理 此实现方式利用了C#中的静态构造函数以及内部...
**Java代码 - 双重检查锁定(Double-Check Locking)单例模式** 在Java编程中,单例模式是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这种模式在需要频繁创建和销毁对象的场景下非常...
单例模式确保某个类只有一个实例,并提供一个全局访问点。 **应用场景**:当系统中只需要一个实例对象时,比如线程池、缓存等。 **优点**: - 保证了系统内存的有效利用。 - 控制对资源的访问。 **缺点**: - ...
5. **单例模式**:单例模式确保一个类只有一个实例,并提供全局访问点。在多线程环境中,单例模式需要正确地处理同步,以防止多个线程同时创建单例对象。 **结构模式** 1. **适配器模式**:适配器模式将一个类的...
这是最严格的单例模式,不仅Activity自身在一个任务栈中唯一,而且这个任务栈中只能有这一个Activity。这意味着任何尝试启动这个Activity的Intent都将在这个Activity所在的任务栈中打开,即使这个Activity已经存在...
描述:C++如何解决单例模式的线程安全问题 ### 关键知识点解析: #### 单例模式的线程安全挑战 单例模式是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。在多线程环境中,传统实现的单例模式可能...
8. **单例模式(Singleton Pattern)**:在游戏编程中,有些资源或服务需要全局唯一,如游戏管理器、音频系统、网络连接等,这就需要用到单例模式来确保只有一个实例存在。 9. **代理模式(Proxy Pattern)**:游戏...
- **单例模式(Singleton)**:确保一个类只有一个实例,并提供一个全局访问点。例如,在Java中`Runtime`类就是单例模式的一个应用。 - **工厂模式(Factory)**:定义一个用于创建对象的接口,让子类决定实例化哪一...
单例模式确保一个类只有一个实例,并提供全局访问点。在PHP中,这个模式常用于管理共享资源,如数据库连接或缓存系统。通过限制实例化次数,单例模式能有效避免资源浪费,提高程序性能。 二、工厂模式 工厂模式...
此外,在Android系统源码中也可以看到多种设计模式的应用,如单例模式在ContextImpl类中的使用,以及观察者模式在BroadcastReceiver中的体现等。 通过学习和实践这些设计模式,不仅可以提高代码质量,还能显著提升...
单例模式确保在整个应用程序中,只有一个SqlSessionFactory实例存在,从而提高性能并减少资源消耗。在实际代码中,可以通过静态工厂方法或双重检查锁定等策略来实现单例。 接下来,我们讨论代理模式。MyBatis的...
- **实现方式**:单例模式共有8种实现方式,包括饿汉式、懒汉式、双重检查锁、静态内部类、枚举等。 - **饿汉式**:在类加载时就完成了初始化,因此类加载比较慢。 - **懒汉式**:第一次调用时才初始化,提高...
正如商标保护法确保了商标的独特性一样,在软件中使用单例模式可以确保某个类的对象在整个系统中只存在一个实例。 #### 二、结构型模式 **5. 适配器模式 (ADAPTER)** - **应用场景**:当希望将一个类的接口转换成...
此外,`taskAffinity`属性可以用来控制Activity所属的任务栈,通常与单例模式配合使用。 通过adb命令,开发者可以查看当前设备上各个任务栈的运行状态,从而更好地理解和调试Activity的启动模式。例如,使用`adb ...
在“追MM”的例子中,单例模式可以比喻为专注于一个人的追求,确保不会出现同时追求多人的情况,保持感情的专一性。 #### 6. 适配器模式(Adapter) 适配器模式是一种结构型设计模式,它作为两个不兼容接口之间的...
1. **单例模式**:就像GG只有一个真心爱慕的MM,系统中也常常需要确保一个类只有一个实例,如全局配置对象。通过双重检查锁定或静态内部类方式实现单例。 2. **工厂模式**:GG追求MM时需要制造惊喜,工厂模式则提供...
1. **单例模式(Singleton)**: - 保证一个类只有一个实例,并提供全局访问点。 - 应用于配置中心、缓存管理等场景。 2. **工厂方法模式(Factory Method)**: - 定义一个创建对象的接口,让子类决定实例化哪...
在Java中,设计模式分为三类:创建型模式(如工厂模式、抽象工厂模式、单例模式)、结构型模式(如适配器模式、代理模式、装饰器模式)和行为型模式(如观察者模式、责任链模式、策略模式)。 这篇博客链接指向的是...
在C++、Java或Python等语言中,实现单例模式有不同的方式,但核心思想是控制类的实例化过程,防止多实例化导致的问题。单例模式常用于资源管理、日志记录等场景,确保在整个程序中只有一个共享的对象。 第三部分则...
例如,"单例模式"可以确保每个Ajax请求只创建一个XMLHttpRequest实例,避免不必要的开销。 6. **错误处理**:良好的Ajax应用应该考虑错误情况,比如网络中断或服务器错误。"异常处理"模式可以帮助优雅地处理这些...