前言
很多人比较熟悉单例模式,而且单例涉及的知识也不少,如果采用同步锁判断实现单例,有如下几点:
- 利用私有访问控制符设置构造函数Constructor,从而禁止通过new创建对象实例。
- 静态成员的类加载过程
- 懒汉模式和饿汉模式
- 多线程的同步锁synchronized效率优化问题
- volatile关键词所涉及的JVM工作内存与主内存的同步问题。
- 序列化和反序列化通过反射创建新的实例对象并返回的问题,以及通过重载readResolve()方法避免返回新实例的方法。
** 如果采用静态内部类只会被加载一次的特性来实现单例模式的话,还需要使用一下知识:**
- 静态内部类与静态成员和静态方法有所不同,静态内部类是在被访问的时候会被有且只有加载一次。
- 静态内部类的加载是由类加载器加载并初始化的,而类加载方法loadClass利用了synchronized 实现同步锁,所以是线程安全的。
** 如果利用枚举来实现当例 **
- 利用枚举的线程安全
- 枚举在序列化和反序列化时不受反射影响
- 枚举实现单例缺点:需要花费至少两倍以上的内存空间,不适合android使用
下面展示单例代码
# 同步锁判断实现单例
public class Singleton {
private static volatile Singleton singleton = null;
private Singleton(){}
public static Singleton getSingleton(){
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
# 避免序列化和反序列化破坏单例模式
private Object readResolve() {
return singleton;
}
}
缺点: 读取效率差,代码相对复杂
# 静态内部类实现单例
public class Singleton {
private static class Holder {
# 存放在静态内部类里面的单例引用
private static Singleton singleton = new Singleton();
}
private Singleton(){}
# 获取单例对象的方法
public static Singleton getSingleton(){
return Holder.singleton;
}
}
缺点: 会被序列化和反序列化破坏单例结构
# 枚举法实现单例
public enum Singleton {
INSTANCE;
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
缺点:需要花费至少两倍以上内存,不适合移动端使用。
网友评论