为什么要使用单例模式
单例的优点
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; }
作者:TryEnough
链接:https://www.jianshu.com/p/4c38969ef2ff
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦