首发安卓设计模式,后期会更加仔细。
IO和数据库等都可以使用单例。
1构造函数不对外开发,一般为Private;
2通过一个静态方法或枚举返回单例对象;
3确保单例类对象只有一个,尤其是在多线程中
4确保单例类对象在反序列化是不会重新构建对象。
//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
private Singleton() {}
private static Singleton sing;
静态工厂方法
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
你可能知道,getInstance()方法中 synchronized关键字,getInstance是一个同步方法,符合了多线程中单例对象一致。但是single即使已经被初始化,每次调用getInstance都会同步进行,消耗了不必要的资源。
DCL单例,其中volatile在之前已经说过了,可以保证无论何时读取这个变量,都是读到内存中最新的值,无论何时写这个变量,都可以立即写到内存中。
public class Singleton {
/**
单例对象实例
*/
private volatile static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
volatile修饰instance时,在编译后,编译器会自动把第二个判断删除,因为编译器判断这个程序在执行过程中,这个值是不会改变的,编译器不考虑多线程的情况。加了volatile,是告诉编译器,这个变量随时有可能会被其他线程改变,这样编译器就不会把这两个判断优化成一个判断了。
DCL优点:资源利用率高,但是第一次加载反应稍慢,由于Java内存模型原因偶尔失败,在高并发环境也有一定缺陷,虽然几率有点小。
/**
*内部静态类实现单例模式
*/
public class Singleton
{
private Singleton(){ }
public static Singleton getInstance()
{
return Nested.instance;
}
//在第一次被引用时被加载
static class Nested
{
private static Singleton instance = new Singleton();
}
public static void main(String args[])
{
Singleton instance = Singleton.getInstance();
}
}
加载类时不会初始化 instance 只有在第一次调用 Singleton的getInstance()才初始化。这种方式确保线程的安全。
枚举单例
public enum SingIetonEnum{
INSTANCE;
public void doSomething(){
System.out.println(“do”);
}
}
写法简单,有自己的方法,创建线程也是安全的。
容器实现单例模式
/**
* 容器单例模式
* @author josan_tang
*/
public class SingIetonManager {
private static Map<String, Object> objMap = new HashMap<String, Object>();
private SingIetonManager(){}
public static void registerService ( String key,Object instance){
if(!objMap.containsKey (key) ){
objMap.put( key ,instance);
}
}
//根据key从集合中得到单例对象
public static Object getSingleton(String key) {
return singletonMap.get(key);
}
}
key获取对象对应类型的对象,这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了耦合度。