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单例模式实现一个简单的日志记录器 #### 一、单例模式简介 单例模式是一种常用的软件设计模式,在该模式中,一个类只能创建一个实例,并且提供了一个全局访问点来访问该实例。单例模式的主要优点包括...
下面是一个简单的DCL实现的懒汉式单例模式代码示例: ```java public class Singleton { private volatile static Singleton instance; // 使用volatile关键字防止指令重排序 private Singleton() {} public ...
单例模式是软件设计模式中的一种经典模式,它在Java、C++、Python等众多编程语言中被广泛应用。单例模式的主要目的是确保一个类只有一个实例,并提供全局访问点,这样可以有效地控制资源的共享,避免因为多次实例化...
以上部分提供了四种不同的单例模式实现代码: 1. **饿汉式单例**(`Singleton1`):类加载时立即实例化,线程安全但效率较低。 2. **非线程安全的懒汉式单例**(`Singleton`):首次调用时实例化,效率高但多线程...
### JAVA设计模式中的单例模式解析 在软件工程与编程领域,设计模式是解决特定问题的一套被广泛接受的解决方案。其中,单例模式(Singleton Pattern)是一种常用的创建型模式,其核心在于确保一个类只有一个实例,...
### PHP 单例模式解析和实战 #### 一、什么是单例模式? 单例模式是一种常用的软件设计模式,尤其在面向对象编程中被广泛应用。它确保一个类只有一个实例,并且提供了一个全局访问点来获取该实例。单例模式在很多...
单例模式的理解与应用 **单例模式**是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。这种模式通常用于控制资源的访问,比如数据库连接、线程池等。 #### 特点: - **唯一性**:确保...
【单例模式详解】 单例模式是设计模式中的一种,它的核心...以上是对单例模式的详细解析,它在Java编程中有着广泛的应用,特别是在需要全局唯一对象的场景中。理解并合理运用单例模式,可以提高代码的可维护性和性能。
总结来说,"经典工厂单例模式典范"是一个将工厂模式和单例模式相结合的经典实例,它在Java、Web和.NET开发中有着广泛的应用。通过学习和理解这个模式,开发者可以更好地组织代码,提高代码的复用性和可维护性,同时...
在Java编程语言中,实现单例模式的方法有很多种,不同的实现方式具有不同的特点和适用场景。本文将详细介绍七种常见的Java单例模式实现方式。 #### 第一种:懒汉式,线程不安全 ```java public class Singleton { ...
Java中有多种方式可以实现单例设计模式,本文将对这些方法进行解析,并提供示例代码。 一、饿汉式单例 饿汉式单例是最简单的一种单例实现方式,它在类加载时就创建了单例对象。其优点是线程安全,但缺点是浪费资源...
单例模式是Java编程中非常重要的一个概念,通过合理的实现方式,不仅可以提高程序的性能,还可以简化系统的复杂度。无论是饿汉式还是懒汉式都有各自的优缺点,在实际应用中需要根据具体情况选择最适合的方式。
Java中实现单例模式有多种方法,常见的有: 1. **饿汉式(推荐)**:在类加载时立即创建实例,线程安全,但可能导致资源浪费。 ```java public class Singleton { private static final Singleton INSTANCE = new ...
需要注意的是,Python的单例模式与Java或C#等语言中的单例有所不同,因为Python的全局解释器锁(GIL)使得多线程环境下依然可以保证单例的线程安全性。然而,如果在多进程环境中,每个进程都有自己的内存空间,那么...
- **静态内部类**:这种方式利用了 Java 类加载机制来确保单例模式的实现,只有当首次调用 `getInstance()` 方法时才会加载静态内部类并初始化单例对象。 - **延迟初始化**:保证了单例对象在真正需要时才被创建。 ...
本文将详细解析一个基于Apache Commons DBCP实现的数据库连接池单例模式代码。 #### 二、基础知识回顾 1. **连接池**:连接池是一种用于管理数据库连接的技术,它预先创建一定数量的数据库连接并存储在一个池中,当...
Java中的单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供全局访问点。在Java中,有五种常见的单例实现模式,每种都有其特定的优点和适用场景。下面将详细介绍这些模式。 1. **饿汉式**: 这...
本篇将详细介绍如何利用枚举(enum)来实现单例模式,并结合`Properties`类解析配置文件。 首先,我们来看一下传统的单例模式实现方式,如懒汉式和饿汉式,但这些方法在多线程环境下可能会存在问题。而使用枚举实现...
【Java 单例模式与抽象工厂模式的结合】 在Java编程中,单例模式和抽象工厂模式都是非常重要的设计模式,它们分别解决了不同的问题。单例模式确保一个类只有一个实例,并提供一个全局访问点,以此来控制对象的创建...