- 传统一般菜鸟知道的两种
/**
* Created by lcqbug on 2016/6/27.
* 饿汉式
*/
public class Singletonhungry {
private static Singletonhungry singletonhungry = new Singletonhungry();//属性就new了个对象出来,缺点,类加载之初,就开辟了对象空间,占用了内存
private Singletonhungry (){
}
/**
* 提供一个静态方法,导致 属性也要 static
* @return
*/
public static Singletonhungry getInstance(){
return singletonhungry;
}
public void doSometing(){
Log.e("lc--",singletonhungry.toString());
}
}
- 1
/**
* Created by lcqbug on 2016/6/27.
*/
public class Singletonlazy {
private static volatile Singletonlazy singletonlazy;//volatile 关键字可以让编译器按部就班的执行代码,不会跳过和省略.(JDK1.5之后)
private Singletonlazy(){
}
/**
* 相比饿汉式,方法调用的时候才实例化对象.可是每次调用都要同步,开销较大,于是对其做改进
* @return
*/
public static synchronized Singletonlazy getInstance(){
// if (singletonlazy == null){
// return new Singletonlazy();
// }else {
// return singletonlazy;
// }
if (singletonlazy == null){
singletonlazy = new Singletonlazy();
}
return singletonlazy;
}
/**
* 改进后的懒汉式,DCL机制(double check lock)
* 一定程度上解决了资源消耗,多余的同步,线程安全的问题.但某些特别的情况下还是会失效(见 Java 并发编程实践),不建议使用,但这种方式应用场景还是蛮多的
* @return
*/
public static Singletonlazy getSingletonlazy(){
if (singletonlazy == null){
synchronized (Singletonlazy.class){
if (singletonlazy == null){
singletonlazy = new Singletonlazy();
}
}
}
return singletonlazy;
}
/**
* http://www.javalobby.org/java/forums/t17491.html
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return singletonlazy;
}
}
- 1
注意 Dcl机制 和 volatile 关键字的使用.但dcl 也不是万能 的,推荐方式呢?
更上一层楼的写法.妙“
public class Singletoninner {
private Singletoninner (){}
private static Singletoninner getSinleoninner(){
return SingletonHolder.singletoninner;
}
private static class SingletonHolder {
private static final Singletoninner singletoninner = new Singletoninner();
}
}
- 1
优化到头了吧,`? 进阶
/**
* Created by lcqbug on 2016/6/27.
*
* 亮瞎me24氪金狗眼的写法,简单至极,并且任何情况下 对象唯一...
*/
public enum SingletonEnum {
SINGLETON_ENUM;
public void doSomething(){
Log.e("lc--","enum---");
}
}
- 1
不禁惊呼,还可以这么写啊! 枚举类型 并且保证了 反序列化 的时候,实例也唯一.而之前的写法 都要重写readResolve()方法
还有吗?学无止境
/**
* Created by lcqbug on 2016/6/27.
* 前面已经让人叹服了,还没完,来看一个脑洞大开的 写法
*/
public class SingletonManager {
private static Map<String,Object> objectMap = new HashMap<>();
private SingletonManager(){
}
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);
}
}
- 1
这种写法可以管理多种类型的单例,并且隐藏了具体实现.
至此,单例完结.畅快淋漓
总结: 不管哪种,共同点 都是 构造方法,属性 私有化,提供一个static的方法给外界调用.还要保证线程安全,防止反序列化导致重新生成实例对象等问题.
选择哪种方式取决于项目本身,考虑 并发环境,JDK版本是否过低,单例资源的消耗等.
优点:
- 减小内存开销
- 较小性能开销
- 避免资源多重占用
- 可以设置全局访问点,优化和共享资源访问
缺点:
- 扩展 只能改 这个 单例类,不可能 通过继承的方式去修改了
- 单例对象如果持有Context,很容易内存泄露,此时传递给 单例对象的Context最好是ApplicationContext
参见android源码设计模式