Singleton
单例模式优点
(1)由于单例模式在内存中只有一种实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或者销毁时性能又无法优化,单例模式的优势就非常明显。
(2)由于单例模式只生成一个实例,所以减少系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永驻内存的方式来解决。
(3)单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
(4)单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。
单例模式缺点
(1)单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
(2)单例对象如果持有Context,那么很容易引发内存泄漏,此时需要注意传递给单例对象的Context最好是Application Context。
/**
* 1,饿汉式单例
*
* @author xiep
*
*/
public class HurrySingleton {
private static final HurrySingleton mInstance=new HurrySingleton();
//私有化构造函数,阻止外部直接实例化对象
private HurrySingleton(){
}
//获取类的单例实例
public static HurrySingleton getInstance(){
return mInstance;
}
}
/**
*,2,懒汉式单例
*
* @author xiep
*
*/
public class LazySingleton {
private static LazySingleton mInstance=null;
//私有化构造函数,阻止外部直接实例化对象
private LazySingleton(){
}
public static synchronized LazySingleton getInstance(){
if(mInstance==null)
mInstance=new LazySingleton();
return mInstance;
}
}
/**
* 3,双重检验加锁单例
*
* 在一定程度上解决了资源消耗,多余的同步,线程安全等问题,
* 但在某些情况下会出现失效问题。
* @author xiep
*
*/
public class DoubleCheckLoackSingleton {
/**
* 加入volatile,保证mInstance对象每次都是从主内存中读取
*/
private volatile static DoubleCheckLoackSingleton mInstance=null;
private DoubleCheckLoackSingleton(){
}
public static DoubleCheckLoackSingleton getInstance(){
if(mInstance==null){//避免不必要的同步
synchronized (DoubleCheckLoackSingleton.class){
if(mInstance==null){//为了在 null的情况下创建实例
/**
* mInstance=new DoubleCheckLoackSingleton()语句并非原子操作;
* 大致做了三件事情:
* 1,给DoubleCheckLoackSingleton的实例分配内存;
* 2,调用DoubleCheckLoackSingleton的构造函数,初始化成员字段;
* 3,将mInstance对象指向分配的内存空间(此时mInstance就不是null了)。
*
* 由于java编译器允许处理器乱序处理,当执行顺序为1-3-2时,DCL会失效,
* JDK1.5及以后只需将mInstance的定义改为 private volatile static DoubleCheckLoackSingleton mInstance=null;
*/
mInstance=new DoubleCheckLoackSingleton();
}
}
}
return mInstance;
}
}
/**
* 4,静态内部类单例模式
*
* 当第一次加载类时不会初始化实例,只有在第一次调用单例的时候getInstance方法才会导致mInstance被初始化。
* 保证线程安全和单例对象唯一性,同时延迟单例的实例化。
*
* @author xiep
*
*/
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton(){
}
public static StaticInnerClassSingleton getInstance(){
return SingletonHolder.mInstance;
}
/**
* 静态内部类
*
* @author xiep
*
*/
private static class SingletonHolder{
private static final StaticInnerClassSingleton mInstance=new StaticInnerClassSingleton();
}
}
/**
* 5,枚举单例
*
* 默认枚举实例的创建是线程安全的,并且在任何情况下它都是一个单例。
* 保证了在反序列化的时候不会重新创建对象。
*
* 通过序列化可以将一个单例的实例对象写到磁盘,然后再读回来,从而有效地获得一个实例。
* 即使构造函数是私有的,反序列化时依然可以通过特殊的途径去创建类的一个新的实例,相当于调用该类的构造函数。
* 反序列化操作提供了一个很特别的钩子函数,类是具有一个私有的、被实例化的方法readResolve(),这个方法可以让开发人员控制对象的反序列化。
*
* 如要杜绝单例对象在被反序列化时重新生成对象,必须加入以下方法:
*
* private Object readResolve() throws ObjectStreamException{
* return mInstance;
* }
*
* @author xiep
*
*/
public enum EnumSingleton {
INSTANCE;
public void doSomething(){
}
}
/**
* 6,使用容器实现单例模式
*
* @author xiep
*
*/
public class SingletonManager {
private static Map<String,Object> objMap=new HashMap<String,Object>();
private SingletonManager(){
}
public static void registerService(String key,Object instance){
if(!objMap.containsKey(key)){
objMap.put(key, instance);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
网友评论