设计模式の单例模式

1、概述

优点:    在内存中只有一个实例,减少了内存开销。

    可以避免对资源的多重占用。

设置全局访问点,严格控制访问。

缺点:    没有接口,扩展困难。

如果要扩展单例对象,只有修改代码,没有其他途径。

2、饿汉式单例

2.1 简述

懒汉模式的写法有好几种,字面理解就是很饥饿,巴不得快点获得。所以都是在类初始化的时候就实例化对象。

缺点也很明显:实际上用不到的实例就比较浪费内存空间。

不过因为虚拟机保证只会装载一次。饿汉式单例在加载类的时候是不存在并发的,所以是没有线程安全问题的。

2.2 饿汉式-普通

public class HungrySingleton {

    private static HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton getInstance() {
        return hungrySingleton;
    }

}

2.3 饿汉式-静态块

public class HungryStaticSingleton {

    private static HungryStaticSingleton hungryStaticSingleton;

    static {
        hungryStaticSingleton = new HungryStaticSingleton();
    }

    private HungryStaticSingleton(){}

    public static HungryStaticSingleton getInstance(){
        return hungryStaticSingleton;
    }

}

3、懒汉式单例

3.1、简述

懒汉式的写法也有好几种。字面理解的意思是很懒,只有用到的时候才去动手实例化。所以是在类调用的时候才去实例化对象。

那么在调用的过程中,会存在多线程并发的问题。所以我们要考虑线程安全的问题。以下就一步步实现它的解决方案。

3.2、懒汉式-普通

public class LazySingleton {

    private static LazySingleton lazySingleton = null;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }

}

3.3、懒汉式-同步方法

下面两种方法是一样的级别,会存在会降低整个访问的速度,而且每次都要判断。

所以更进一步的写法是:3.4、双重检查锁。

public class LazySingleton {

    private static LazySingleton lazySingleton = null;

    private LazySingleton(){}

    public static synchronized LazySingleton getInstance(){
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }

}
public class LazySingleton {

    private static LazySingleton lazySingleton = null;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if(lazySingleton == null){
            synchronized (LazySingleton.class) {
                lazySingleton = new LazySingleton();
            }
        }
        return lazySingleton;
    }

}

3.4、懒汉式-双重检查锁

这种实现方式既线程安全地创建实例,又不会对性能造成太大的影响。

它只是在第一次创建实例的时候同步,以后就不需要同步了,从而加快了运行速度。

public class LazySingleton {

    //被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
    private static volatile LazySingleton lazySingleton = null;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if(lazySingleton == null){
            synchronized (LazySingleton.class) {
                //这里不加判断的话,多个线程等其中有的线程执行完了之后,后面执行的线程还是会进来执行,又生成新的实例。
                if(lazySingleton == null) {
                    lazySingleton = new LazySingleton();
                }
            }
        }
        return lazySingleton;
    }

}

4、破坏单例模式

4.1、反射

通过反射获取的类和实例化的对象不一样。

解决办法:禁止通过骚操作去实例化对象。

4.2、序列化

通过将类转化为文件后,再序列化回来,发现两者的对象不一样。

解决办法:在实例化中通过重写readsolve方法可以解决这个问题。

 

5、注册式单例

5.1、枚举式

jvm底层对枚举类做了更多的优化

5.2、容器式

 

5.3、ThreadLocal单例

保证线程内部的全局唯一,且天生线程安全

 

6、总结

  1. 私有化构造器
  2. 保证线程安全
  3. 延迟加载
  4. 防止序列化和反序列化破坏单例
  5. 防御反射攻击单例

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值