Singleton模式和它的变体Double-Checked Locking模式比较简单,而且非常常用.
按照<设计模式>一书 ,singleton 意图:保证一个类有且仅有一个实例,并对外提供一个访问它的全局访问点.
其具体的关键特征和工作原理,不在此文表述,可以参看<Design Patterns Explained>一书.
以下逐步提供代码实现:
代码1, 最经典的实现: 把class中所有的methods和fields/status全部声明为static,
然后初始化还可以用static关键字,显示的初始化.
(有兴趣的请参见<Thinking.In.Java.4th.Edition>一书中的节Explicit static initialization)
代码1:
public class StaticSingleton {
public static int count =0;
private static String name =null;
static {
name = "singleton";
}
public static String getName() {
return name;
}
public static void setName(String name) {
StaticSingleton.name = name;
}
}
假设该StaticSingleton 有许多的methods和fields/status,那么我们的代码就有所多static关键字了.
这样对于声明的methods和fields/status都要打上static关键字.似乎有点累,
书写代码后,看来似乎有点不美观,
且对于JDK6开始,StaticSingleton 对外的引用全要写成StaticSingleton.A ,或StaticSingleton.getA()之类的,
让StaticSingleton 的局外使用不够简洁.
那么产生代码2.
代码2: Eager式的Singleton (实际上多线程不可行)
public class EagerSingleton1 {
private static EagerSingleton1 instance;
private EagerSingleton1() {
}
public static EagerSingleton1 getInstance() {
if( instance == null ) instance = new EagerSingleton1();
return instance;
}
}
带父类的.
示例:
public class EagerSingleton1 extends SuperSingleton {
private static SuperSingleton instance;
private EagerSingleton1() {
}
public static SuperSingleton getInstance() {
if( instance == null ) instance = new EagerSingleton1();
return instance;
}
}
代码2, 只能用于单线程情况,假设多线程情况下,那么就会出现问题.
如两个线程都执行EagerSingleton1 的new 操作,那后果就可以想象一下.
因此在多线程下我们加入线程同步代码像 代码4 或 代码3.
代码3:
public class EagerSingleton {
//是否带final,视情况而定.
private static EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return instance;
}
}
带父类的代码(略).
代码4. (针对JAVA,多线程还是不可行,原因JAVA编译器本身优化工作)
针对代码2解决方法:在检查null之后进行同步(doSync()),然后再检查一次,确保实例尚未创建.
这就称为Double-Checked Locking模式.
实际上这是C++转换成JAVA的.
代码4: 可以带父类的
public class LazySingleton extends SuperSingleton {
// 是否带final,视情况而定.
private static volatile LazySingleton instance = null;
private LazySingleton() {
}
public static SuperSingleton getInstance() {
if( instance == null ) {
synchronized (LazySingleton.class) {
if( instance == null ) {
instance = new LazySingleton();
}
}
}
return instance;
}
//private synchronized static void doSync() {
// if( instance == null ) instance = new LazySingleton();
//}
}
根据Java的语言规范,上面的代码是不可靠的。
出现上述问题, 最重要的2个原因如下:
1, 编译器优化了程序指令, 以加快CPU处理速度.
2, 多核CPU动态调整指令顺序, 以加快并行运算能力.
问题出现的顺序:
1, 线程A, 发现对象未实例化, 准备开始实例化
2, 由于编译器优化了程序指令, 允许对象在构造函数未调用完前, 将 共享变量的引用指向 部分构造的对象, 虽然对象未完全实例化, 但已经不为null了.
3, 线程B, 发现部分构造的对象已不是null, 则直接返回了该对象.
不过, 一些著名的开源框架, 包括jive,lenya等也都在使用DCL模式, 且未见一些极端异常.
说明, DCL失效问题的出现率还是比较低的.
利用JAVA ClassLoader ,JRE自身特点,产生代码5.
(有兴趣的可以看看IBM和sun网写的java classLoader文章和有关类加载顺序)
代码5: 可以带父类的 // 会生成文件Singleton.class和Singleton$Instance.class
public class Singleton extends SuperSingleton {
//内部类,将只被装载一次.
private static class Instance {
//final关键字
static final SuperSingleton instance = new Singleton();
}
private Singleton() {
}
public static SuperSingleton getInstance() {
return Instance.instance;
}
//暂未使用Singleton instance
private static Singleton instance;
public void doA() {
}
public void doB() {
}
//危险代码.
protected void finalize(){
//置空操作
}
}
代码5, 是对于单线程或多线程都是可行的.
更符合类间关系的原则,对于对象A,A要么只创建B类,要么只使用B类的方法,不要二者兼之.
然后试试对代码5的使用感受吧.
注:另外针对从代码2到代码5,在ECLIPSE下是可以自己创建代码模板,供生成代码2到代码5.
在此不提供,让大家自己熟悉代码.
模板位置:eclipse->windows->preferrence->java->editors->templates->...
最后快捷键:ALT+/
参考资料:
1. book: design pattern explains.
2. books and papers : java memory model
3. java class loader
http://java.sun.com/developer/technicalArticles/Networking/classloaders/
http://download.oracle.com/javase/tutorial/ext/basics/load.html
http://www.ibm.com/developerworks/cn/java/j-lo-classloader/?ca=drs-tp4608
https://docs.google.com/viewer?a=v&q=cache:XhllCyQFTS0J:www.freejavaguide.com/jcl.pdf+java+classloader+ibm&hl=zh-CN&pid=bl&srcid=ADGEESiOaJjb2W-ilYRra4XOQEV4xbG1risXhRXdxtY0qYnhryvduOsLQapuQDdh1-A8frGy0cAqGNMV4vt8x-q_TLAoqgOKWpA1dlbn-6l_Jm3z2I6AvOLiXCztNafc_dx72C1hLzz0&sig=AHIEtbStlkg0vB89MsPd_YQQgHnpcrKn7A&pli=1
分享到:
相关推荐
主要介绍了java单例五种实现模式解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
它的讲解思路为:模式动机->模式定义->模式结构->模式分析(即原理)->实例解析->模式优缺点->模式使用场景->模式应用->模式扩展。采用图文+文字+实例的方式,让读者不仅知其然,还能知其所以然。读后有种豁然开朗的...
主要介绍了Java实现单例设计模式方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了Java设计模式单例模式(Singleton)用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
本文将对 Java 设计模式面试题进行解析,涵盖了单例模式、观察者模式、工厂模式、装饰器模式等常见设计模式,并对每个模式的定义、应用场景和实现方式进行了详细的解释。 一、单例模式(Singleton pattern) 单例...
在本文中,我们将对 10 道 Java 面试必备的设计模式面试题进行详细的解析,涵盖了单例模式、观察者模式、工厂模式、装饰器模式等多种设计模式。 1. JDK 中常用的设计模式 在 JDK 中,有多种常用的设计模式,例如...
本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)...进阶篇有反射、泛型、注解、网络编程、多线程、序列化、数据库、Servlet、JSP、XML解析、单例模式与枚举。本专栏主要为Java入门者提供实验参考。
本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)...进阶篇有反射、泛型、注解、网络编程、多线程、序列化、数据库、Servlet、JSP、XML解析、单例模式与枚举。本专栏主要为Java入门者提供实验参考。
单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式 适配器模式、装饰者模式、代理模式、外观模式、桥接模式、组合模式、享元模式观察者模式、策略模式、模板模式、责任链模式、解析器模式、迭代子模式 ...
单例模式是一种创建型模式,确保一个类只有一个实例,并提供一个全局访问点。例如,数据库连接、在线人数记录等。单例模式节省资源,控制了实例对象的个数,并有助于 GC 回收。 b) 方略模式: 策略模式是一种行为...
秒杀项目练习 :seckill 该项目总体架构: Maven + SSM 日志: slf4j + logback 数据库相关:Mysql + c3p0 权限控制项目练习:springboot-shiro ...配置模块:单例模式,dom4j解析xml,IOC控制反转
* 如何在 Java 中实现单例模式?使用静态变量和同步机制实现单例模式。 16. Java GC * Java 中什么是 GC?GC(Garbage Collector)是 Java 的垃圾回收机制。 * 如何进行垃圾回收?使用 System.gc() 方法请求垃圾...
单例模式(饿汉式、懒汉式) 4. Linux的基础知识 Linux下的进程 Linux定时任务调度 Linux的七个运行级别 Linux进程启动顺序 深入理解Linux下的守护进程 理解Linux配置文件 下一阶段更新计划 增加JDK源码的注释 + ...
* 实现单例模式。 * 实现策略模式。 注解 注解是 Java 语言中的一种元数据,用于提供某些信息给编译器或 runtime 环境。注解可以用来生成文档、格式检查、跟踪代码依赖性等。 注解的定义 在 Java 中,注解是使用...
线程 单例模式下的线程安全http://blog.sina.com.cn/s/blog_75247c770100yxpb.html map集合 集合数据结构及方法的使用 多线程 线程进程 线程状态 线程状态的改变 sql :临时表、游标、存贮过程、触发机制...
本地代码实现的类加载器,它负责将 <JAVA_HOME>/lib下面的核心类库 或 -Xbootclasspath选项指定的jar包等 虚拟机识别的类库 加载到内存中。 由于引导类加载器涉及到虚拟机本地实现细节,开发者...
使用Map的工厂函数同时也是一个单例模式的应用。相较于在条件语句中创建实例,该方法更节省内存空间。 工厂模式 工厂模式实际上是对简单工厂模式的进一步封装,其目的在于将复杂类的创建从工厂类中剥离出去,并...
如何控制两种框架中的单例模式? 74 73. Spring 75 73.1. Spring 简介 75 73.2. 为什么要用Spring? 76 73.3. spring工作机制或工作原理 76 73.4. Spring是什么?根据你的理解详细谈谈你的见解。 76 73.5. 项目中如何...
线程 单例模式下的线程安全http://blog.sina.com.cn/s/blog_75247c770100yxpb.html map集合 集合数据结构及方法的使用 多线程 线程进程 线程状态 线程状态的改变 sql :临时表、游标、存贮过程、触发机制...
在 Java 中,可以使用各种设计模式和技术来实现不同的功能,例如单例模式、工厂模式、代理模式等。单例模式是一种常见的设计模式,通过单例模式可以保证一个类只有一个实例,例如: public class Singleton { ...