原文链接
更多教程
为什么要使用单例模式
单例的优点
1.只有一个实例,节省开销
2.全局使用方便,同时避免频繁创建和销毁
使用单例的注意点:
要避免造成 内存泄漏
常用的单例模式
单例不仅要满足线程安全,还要注意防止序列化产生新对象。如果单例实现了Serializable接口,就必须加入如下方法(枚举单例不用这么做,因为JVM能保障这点):
private Object readResolve() throws ObjectStreamException{
return INSTANCE;
}
原文链接
更多教程
饿汉式
饿汉式:就是在类初始化时就实例化,所以是线程安全的。
缺点是:
1.没有懒加载,在不需要的时候也会被实例化,造成内存浪费。
2.实例化方法对外部调用不友好,传参不方便
public class Singleton implements Serializable {
private static final Singleton INSTANCE = new Singleton();
// 私有化构造函数
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
/**
* 如果实现了Serializable, 必须重写这个方法
*/
private Object readResolve() throws ObjectStreamException {
return INSTANCE;
}
}
懒汉式
延迟加载(使用时加载),节省内存
双重判空,第一次判空防止重复加锁,第二次判空才实例化
防止DCL指令重拍序,加volatile关键字
public class Singleton {
private volatile static Singleton INSTANCE; //声明成 volatile
private Singleton (){}
public static Singleton getSingleton() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
//如果实现了Serializable, 必须重写同上面饿汉式一样的readResolve方法
枚举式
由JVM保证线程安全
序列化和反射攻击已经被枚举解决
//enum枚举类
public enum Singleton {
INSTANCE;
public void yourMethod() {
}
}
内部类实现单例
当Singleton被加载时,其内部类并不会被初始化,故可以确保当 Singleton类被载入JVM时,不会初始化单例类。只有 getInstance() 方法调用时,才会初始化 instance。同时,由于实例的建立是时在类加载时完成,故天生对多线程友好,getInstance() 方法也无需使用同步关键字。
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,
* 而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder{
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static final Singleton instance = new Singleton();
}
/**
* 私有化构造方法
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
网友评论