原文地址:http://leihuang.org/2014/12/05/singleton/
Creational 模式
物件的产生需要消耗系统资源,所以如何有效率的产生、管理 与操作物件,一直都是值得讨论的课题, Creational 模式即与物件的建立相关,在这个分类下的模式给出了一些指导原则及设计的方向。下面列举到的全属于Creational 模式
- Simple Factory 模式
- Abstract Factory 模式
- Builder 模式
- Factory Method 模式
- Prototype 模式
- Singleton 模式
- Registry of Singleton 模式
当程序中要求只需要一个单例的时候,那么此时就需要使用单例模式,如果没有这种要求,那么就不需要使用单例模式.
懒汉式和饿汉式
我们先来两个常见的单例模式,懒汉式和饿汉式.
//懒汉式
public class SingletonLazy {
private static SingletonLazy single = null ;
private SingletonLazy(){
}
synchronized public static SingletonLazy getInstance(){
if(single == null){
single = new SingletonLazy() ;
}
return single ;
}
}
//饿汉式
public class SingletonHunger {
private static SingletonHunger single = new SingletonHunger() ;
private SingletonHunger(){
}
public static SingletonHunger getInstatnce(){
return single ;
}
}
注意,懒汉式单例类实现里对静态工厂方法使用了同步化,以处理多线程环境.
优化版的饿汉式
其实单例模式很简单,但是它涉及到的很多知识就非常复杂了.比如饿汉式虽然解决了多线程安全的问题,不需要使用同步(提高了效率),但是它 却浪费了内存,因为SingletonHunger类装载的时候就初始化了对象,此时我们就可以利用内部类的机制来解决这个问题.
public class SingletonInner {
private static InnerInstance{
private static SingletonInner single = new SingletonInner() ;
}
private SingletonInner(){
}
public static SingletonInner getInstance(){
return InnerInstance.single ;
}
}
上面的代码中又涉及到不少知识.
- 内部类声明为static的意义:不需要初始化外部内的情况下就能被使用;
- 内部类在自己被使用的时候才会被装载,外部内被初始化,但其内部类并未被初始化.详见这里
- 类什么时候被加载/类加载时机:第一:生成该类对象的时候,会加载该类及该类的所有父类;第二:访问该类的静态成员的时候;第三:class.forName("类名");
优化版的懒汉式
我们知道懒汉式对于饿汉式的有点在于节约了空间,但其利用同步来解决线程安全性问题,很大程度的降低了程序的效率.
于是我们就想到如何来提高懒汉式的效率,首先它依然还是必须要有同步在里面.
有一种方法就双重检查机制,这个广泛应用在c语言中,但是它在java中却是错误的,如果你上锁的是基本类型的话,是没有问题的,但是你如果锁定的是对象的话就有问题了.但是我们此处是讲单例模式,所以锁的肯定是对象而不是int,long,double等类型数据了.
如下代码是错误的.
public class SingletonLazy01 {
private static SingletonLazy01 single = null ;
private SingletonLazy01(){
}
public static SingletonLazy01 getInstance(){
if(single == null){
synchronized(SingletonLazy01.class){
if(single == null){
single = new SingletonLazy01() ;
}
}
}
return single ;
}
}
我们利用volatile关键字
public class SingletonLazy01 {
private volatile static SingletonLazy01 single = null ;
private SingletonLazy01(){
}
public static SingletonLazy01 getInstance(){
if(single == null){
synchronized(SingletonLazy01.class){
if(single == null){
single = new SingletonLazy01() ;
}
}
}
return single ;
}
}
至于双重检查问题详见这里--->双重检查锁定与延迟初始化
2014-12-05 19:52:59
Brave,Happy,Thanksgiving !