单例模式保证了在应用中只有一个实例的存在,比如在一个应用中,只需要一个ImageLoader实例。
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
确保某个类又切只有一个对象的场景,避免产生多个对象耗费过多的资源。当创建一个对象需要消耗的资源过多时,就要考虑用单例设计模式。
如一个公司只有一个ceo,一个应用中只有一个Application
构造函数不对外开放,private(客户端不能通过new重新创建对象)。
通过静态方法或者枚举返回单例类对象(需要确保线程安全)。
确保单例类的对象有且只有一个。
确保单例对象在反序列化时不会重新创建对象。
声明时初始化
public class Staff{
public void work(){}
}
public class VP extends Staff{
}
public class CEO extends Staff{
private static final CEO mCeo= new CEO();
private CEO(){}
public static CEO getmCeo{
return mCeo;
}
}
其中VP和Staff不是单例的,CEO是单例的,只有一个对象。
第一次调用时初始化
public class Singleton {
// 1.一个私有的指向自己的静态变量
private static Singleton instance;
// 2.私有的构造方法,保证不能从外部创建对象
private Singleton(){}
// 3.公开的静态工厂方法,返回该类的唯一实例(当发现没有实例没有初始化的时候才初始化)
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
优点:初始化才创建
缺点:每次都需要检查同步,消耗资源
public class LockSingleton{
private volatile static LockSingleton singleton;
private LockSingleton(){}
//http://www.ibm.com/developerworks/cn/java/j-dcl.html
public static LockSingleton getInstance(){
if(singleton==null){
synchronized(LockSingleton.class){
if(singleton==null){
singleton=new LockSingleton(); //非原子性操作
}
}
}
return singleton;
}
}
singleton=new LockSingleton();是非原子性操作,分为3个步骤
其中 2 和 3 顺序是未定的,容易引起DCL失效,需要借助volatile关键字解决这个问题
优点:初始化才实例化,效率高
缺点:第一次翻译稍慢
class InternalSingleton{
private static class SingletonHolder{
private final static InternalSingleton INSTANCE=new InternalSingleton();
}
private InternalSingleton(){}
public static InternalSingleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
优点:调用时才初始化静态变量INSTANCE,,也有效避免了DCL失效 ,所以推荐使用这种方式。
/** * 《Effective Java》作者推荐使用的方法,优点:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象 */
enum EnumSingleton{
INSTANCE;
public void doSomeThing(){
}
}
反序列化可以通过复写钩子函数:readResolve(),返回单例对象,默认会重新生成一个新的对象。
另类的单例实现,将单例类型注入到一个统一的管理类中,再根据key获取对象对应类型的对象。也称为登记式单例
public class SingletonManager {
private SingletonManager() {
}
private static Map<String, Object> objectMap = new HashMap<>();
public static void registerService(String key,Object instance){
if (!objectMap.containsKey(key)){
objectMap.put(key,instance);
}
}
public static Object getService(String key){
return objectMap.get(key);
}
}
在android系统中,我们经常会通过Context获取系统的服务,如WindowsManagerService、ActivityManagerService、LayoutInflater等。
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);