线程安全的单例模式
2012-11-15 00:00
639 查看
线程安全的单例模式
1. 全局变量的缺点:
必须在程序一开始就创建好对象,如果程序在这次的执行过程中又一直没用到它,就非常耗费资源。
2. 经典的单例模式实现:
Java代码
public class Singleton {
//用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
private Singleton() {}
//注意这个方法也是静态的
public <SPAN style="COLOR: #ff0000">static</SPAN> Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
[b][java]
view plain
copy
?
public class Singleton {
//用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
private Singleton() {}
//注意这个方法也是静态的
public <SPAN style="COLOR: #ff0000">static</SPAN> Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
public class Singleton { //用一个静态变量来记录Singleton类的唯一实例 private static Singleton uniqueInstance; private Singleton() {} //注意这个方法也是静态的 public static Singleton getInstance() { if(uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } }
单例常被用来管理共享的资源,例如数据库连接、线程池、缓存、注册表。
单例模式确保一个类只有一个实例,并提供一个全局访问点。
这个模式的问题:在多线程时,并不能保证这个类只被实例化一次。
3. 处理多线程:
public class Singleton {
Java代码
//用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
private Singleton() {}
//注意这个方法也是静态的
public static <SPAN style="COLOR: #ff0000">synchronized</SPAN> Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
[java]
view plain
copy
?
//用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
private Singleton() {}
//注意这个方法也是静态的
public static <SPAN style="COLOR: #ff0000">synchronized</SPAN> Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
通过增加synchronized关键字到getInstance()方法中,迫使每个线程在进入方法之前,要先等别的线程离开该方法。也就是说,不会有两个线程可以同时进入这个方法。//用一个静态变量来记录Singleton类的唯一实例 private static Singleton uniqueInstance; private Singleton() {} //注意这个方法也是静态的 public static synchronized Singleton getInstance() { if(uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } }
这种方法存在的问题:只有第一次执行此方法时,才真正需要同步。换句话说,一旦设置好uniqueInstance变量,就不再需要同步这个方法了。之后每次调用这个方法,同步都是一种浪费。
4.改善多线程
4.1 如果getInstance()的性能对应用程序不是很关键,就不用优化了
4.2 使用急切创建实例,而不用延迟实例化的做法
Java代码
public class Singleton {
<SPAN style="COLOR: #ff0000">private static Singleton uniqueInstance = new Singleton();</SPAN>
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}
[java]
view plain
copy
?
public class Singleton {
<SPAN style="COLOR: #ff0000">private static Singleton uniqueInstance = new Singleton();</SPAN>
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}
标红的语句在静态初始化器(static initializer)中创建单例,这保证了线程安全。public class Singleton { private static Singleton uniqueInstance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return uniqueInstance; } }
利用这个做法,JVM在加载这个类时马上创建此唯一的单件实例。JVM保证任何线程访问uniqueInstance静态变量之前,一定先创建些实例。
4.3 用“双重检查加锁”,在getInstance()中减少使用同步
首先检查实例是否已经创建,如果尚未创建,才进行同步。这样一来,只有第一次会同步,这正是我们想要的。
Java代码
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if(uniqueInstance == null) { //(1)
//只有第一次才彻底执行这里的代码
synchronized() {
//再检查一次
if(uniqueInstance == null)
uniqueInstance = new Singleton();
}
}
return uniqueInstance;
}
}
[java]
view plain
copy
?
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if(uniqueInstance == null) { //(1)
//只有第一次才彻底执行这里的代码
synchronized() {
//再检查一次
if(uniqueInstance == null)
uniqueInstance = new Singleton();
}
}
return uniqueInstance;
}
}
在最开始如果有1、2、3个线程走到了(1)处,假设1进入了同步块,2、3等待。1实例化后,2进入同步块,发现uniqueInstance已经不为空,跳出同步块。接着3进入,又跳出同步块。public class Singleton { private volatile static Singleton uniqueInstance; private Singleton() {} public static Singleton getInstance() { if(uniqueInstance == null) { //(1) //只有第一次才彻底执行这里的代码 synchronized() { //再检查一次 if(uniqueInstance == null) uniqueInstance = new Singleton(); } } return uniqueInstance; } }
volatile关键字确保:当uniqueInstance变量被初始化成Singleton实例时,多个线程正确地uniqueInstance变量。如果性能是你关心的重点,那么这个做法可以帮你大大地减少getInstance()的时间耗费。
[/b]
相关文章推荐
- 单例模式实现 线程安全的队列 处理
- Spring中Singleton模式的线程安全
- Java 单例模式线程安全
- Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。
- 转-Android网络(4):HttpClient必经之路----使用线程安全的单例模式HttpClient,及HttpClient和Application的融合
- C++线程安全的单例模式
- Java基础学习总结(85)——Java中四种线程安全的单例模式实现方式
- 高并发下线程安全的单例模式(最全最经典)
- 线程安全的单例模式的实现
- 单例模式下如何保证是线程安全的
- 利用双重检查加锁机制实现线程安全的单例模式
- 单例模式的线程安全
- Spring中Singleton模式的线程安全
- iOS 单例模式 学习 "52个方法 第6章 45条 使用 dispath_once 来执行只需运行一次的线程安全代码"
- C++ 线程安全的单例模式
- C++ 线程安全的单例模式
- javaSE-单例设计模式的线程安全
- java中线程安全的单例模式
- C++ 单实例模式 线程安全
- 解决单例设计模式中的懒汉设计模式存在线程安全问题(并且在一定程度上提高效率)的一种解决方法