同步
线程安全的例子----只要像下面一个同步化getInstance()方法:
Java代码
public synchronized static Singleton getInstance() {
if(singleton == null) {
singleton = new Singleton();
}
logger.info("created singleton: " + singleton);
return singleton;
}
在同步化getInstance()方法后,我们就可以得到例5的测试案例返回的下面的结果:
Java代码
1. Buildfile: build.xml
2.
3. init:
4. [echo] Build 20030414 (14-04-2003 03:15)
5.
6. compile:
7. [javac] Compiling 2 source files
8.
9. run-test-text:
10. INFO Thread-1: sleeping...
11. INFO Thread-1: created singleton: Singleton@ef577d
12. INFO Thread-2: created singleton: Singleton@ef577d
13. [java] .
14. [java] Time: 0.513
15.
16. [java] OK (1 test)
Buildfile: build.xml
init:
[echo] Build 20030414 (14-04-2003 03:15)
compile:
[javac] Compiling 2 source files
run-test-text:
INFO Thread-1: sleeping...
INFO Thread-1: created singleton: Singleton@ef577d
INFO Thread-2: created singleton: Singleton@ef577d
[java] .
[java] Time: 0.513
[java] OK (1 test)
这此,这个测试案例工作正常,并且多线程的烦恼也被解决;然而,机敏的读者可能会认识到getInstance()方法只需要在第一次被调用时同步。因为同步的性能开销很昂贵(同步方法比非同步方法能降低到100次左右),或许我们可以引入一种性能改进方法,它只同步单例类的 getInstance()方法中的赋值语句。
一种性能改进的方法
寻找一种性能改进方法时,你可能会选择像下面这样重写getInstance()方法:
Java代码
public static Singleton getInstance() {
if(singleton == null) {
synchronized(Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
这个代码片段只同步了关键的代码,而不是同步整个方法。然而这段代码却不是线程安全的。考虑一下下面的假定:线程1进入同步块,并且在它给 singleton成员变量赋值之前线程1被切换。接着另一个线程进入if块。第二个线程将等待直到第一个线程完成,并且仍然会得到两个不同的单例类实例。有修复这个问题的方法吗?请读下去。
双重加锁检查
初看上去,双重加锁检查似乎是一种使懒汉式实例化为线程安全的技术。下面的代码片段展示了这种技术:
Java代码
public static Singleton getInstance() {
if(singleton == null) {
synchronized(Singleton.class) {
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
如果两个线程同时访问getInstance()方法会发生什么?想像一下线程1进行同步块马上又被切换。接着,第二个线程进入if 块。当线程1退出同步块时,线程2会重新检查看是否singleton实例仍然为null。因为线程1设置了singleton成员变量,所以线程2的第二次检查会失败,第二个单例类实例也就不会被创建。似乎就是如此。
不幸的是,双重加锁检查不会保证正常工作,因为编译器会在Singleton的构造方法被调用之前随意给singleton赋一个值。如果在singleton引用被赋值之后而被初始化之前线程1被切换,线程2就会被返回一个对未初始化的单例类实例的引用。
一个改进的线程安全的单例模式实现
例7列出了一个简单、快速而又是线程安全的单例模式实现:
例7.一个简单的单例类
Java代码
public class Singleton {
public final static Singleton INSTANCE = new Singleton();
private Singleton() {
// Exists only to defeat instantiation.
}
}
这段代码是线程安全的是因为静态成员变量一定会在类被第一次访问时被创建。你得到了一个自动使用了懒汉式实例化的线程安全的实现;你应该这样使用它:
Java代码
1. Singleton singleton = Singleton.INSTANCE;
2. singleton.dothis();
3. singleton.dothat();
4. ...
Singleton singleton = Singleton.INSTANCE;
singleton.dothis();
singleton.dothat();
...
当然万事并不完美,前面的Singleton只是一个折衷的方案;如果你使用那个实现,你就无法改变它以便后来你可能想要允许多个单例类的实例。用一种更折哀的单例模式实现(通过一个getInstance()方法获得实例)你可以改变这个方法以便返回一个唯一的实例或者是数百个实例中的一个.你不能用一个公开且是静态的(public static)成员变量这样做.
参考:单例模式完全剖析 http://www.iteye.com/topic/60179
分享到:
相关推荐
简单的单例模式举例Singleton 分为恶汉式 懒汉式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个...
单例模式的特点有三: 单例类只能有一个实例。 单例类必须自己创建自己的唯一实例。 单例类必须给所有其他对象提供这一实例。 Singleton模式包含的角色只有一个,就是Singleton。Singleton拥有一个私有构造函数,...
设计模式C++学习之单例模式(Singleton)
java Singleton单例模式 java Singleton单例模式
此示例展示了Qml 的单例模式(类似全局对象,只生成一次实例,可全局使用) surfsky.cnblogs.com
单例模式 Singleton 单例模式线程安全问题和拓展
单例模式(Singleton)
一个产生随机数的例子,整个应用程序中只需要一个类的实例来产生随机数,客户端程序从类中获取这个实例,调用这个实例的方法nextInt(),公用的方法访问需要进行同步,这是单例模式需要解决的同步问题。
单例模式(Singleton)的6种实现,单例模式(Singleton)的6种实现
Java面向对象(高级)-- 单例(Singleton)设计模式
该文当中对Java单类模式有非常细致入微的,循序渐进的讲解。
主要介绍了单例模式 Singleton 简单实例设计模式解析的相关资料,需要的朋友可以参考下
在Java应用中,单例对象能保证在一个...3、有些像交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了,只有使用单例模式,才能保证核心交易服务器独立控制整个流程。 CSDN代码的详细解释。
设计模式总结-模板设计模式,单例模式(singleTon)
4、单例模式(Singleton Pattern) 用意:仅允许生成一个对象时
四种常见的单例: 1、没有构造函数(DEFINE_SINGLETON_DEFAULT); 2、有构造函数,构造函数没有参数(DEFINE_SINGLETON_CONSTRUCT_NO_PARAM); 3、有构造函数,构造函数有没有参数版本(DEFINE_SINGLETON_...
深入浅出Singleton,详细掌握单例模式
如:IO处理,数据库操作等,由于这些对象都要占用重要的系统资源,所以我们必须限制这些实例的创建或始终使用一个公用的实例,这就是我们今天要介绍的——单例模式(Singleton)。 使用频率高 单件模式(Singleton...