JAVA 设计模式学习笔记(二)--单例模式

单例模式

1. 定义

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

2. 具体实现

2.1 饿汉式(静态常量)

优点:在类加载的时候就完成了实例化,避免了线程同步的问题

缺点:没有达到lazy loading的效果,如果没有用到这个实例,就会造成内存的浪费

public class case1 {
    private static final case1 single = new case1();

    //私有化构造方法,不让外部能够创建
    private case1(){

    }
    //通过调用静态方法获取实例
    public static case1 getInstance(){
        return single;
    }
}
2.2 饿汉式(静态代码块)

优缺点和静态变量的类似

public class case2 {
    private static case2 single;
    //在静态代码块中创建并初始化单例对象,和静态变量类似,都是在类装载的时候初始化
    static  {
        single = new case2();
    }
    //私有化构造方法,不让外部能够创建
    private case2(){

    }
    //通过调用静态方法获取实例
    public static case2 getInstance(){
        return single;
    }
}
2.3 懒汉式(线程不安全)

优点:懒加载

缺点:线程不安全,只能在单线程下使用

public class case3 {
    private static case3 single;
    //私有化构造方法
    private case3(){

    }
    //获取实例
    public static case3 getInstance(){
        //只有当single为空的时候才创建,这里就是线程不安全的地方
        //一个线程进入了if,还没来得及创建实例,此时,另一个线程来了,发现single是null于是又去创建了示例
        if(single == null){
            single = new case3();
        }
        return single;
    }
}
2.4 懒汉式(线程安全 – synchronized)

优点:相比于第3个方法,确实是现场安全了

缺点:同时只有一个线程能够获取实例,效率大大的降低了

public class case4 {
    private static case4 single;
    //私有化构造方法
    private case4(){

    }
    //获取实例,通过添加线程同步块来确保现场安全
    //加上了synchronized之后同时只有一个线程能够调用getInstance,因此确保的线程的安全
    public static synchronized case4 getInstance(){
        if(single == null){
            single = new case4();
        }
        return single;
    }
}
2.5 懒汉式(同步代码块 – 线程不安全)

优点:不会像4一样每次都对方法加锁

缺点:线程不安全–我们无法保证if语句和synchronized语句块之间的这段时间是现场安全的

也就是说有可能一个线程进来发现single为空,进入if语句,此时因为一些原因,线程进入等待状态.之后另一个线程进来也发现single为空,这个线程成功的new的case5对象.之后,前一个线程结束等待,继续从if之后synchronized语句块之前执行,它也会去new一个case5对象,此时问题就发生了.

public class case5 {
    private static case5 single;
    //私有化构造方法
    private case5(){

    }
    //获取实例,通过添加线程同步块来确保现场安全
    public static case5 getInstance(){
        //这种写法仍然不能保证线程安全
        if(single == null){
            //用类对象来上锁
            synchronized(case5.class){
                single = new case5();
            }
        }
        return single;
    }
}
2.6 懒汉式(双重检查)

优点:懒加载,且线程安全,效率也很不错

    //volatile 千万别忘记 没有这个关键字仍然可能线程不安全
	//它的作用是使CPU每次使用这个对象的时候不从缓存中取,而是直接从内存中取
	//在赋值的时候也会及时的刷入内存
    private static volatile case6 single;
    //私有化构造方法
    private case6(){

    }
    //获取实例,通过添加线程同步块来确保现场安全
    public static case6 getInstance(){
        //这种写法仍然不能保证线程安全
        if(single == null){
            //用类对象来上锁
            synchronized(case6.class){
                //再加一次检查,可以保证现场安全
                if(single == null) {
                    single = new case6();
                }
            }
        }
        return single;
    }
2.7 静态内部类

优点:懒加载,高效,线程安全,没有多余的检查逻辑和同步逻辑

public class case7 {

    private case7(){

    }
    //静态内部类不随外部类的装载而装载,只有当我们第一次使用getInstance的时候,静态内部类才会装载
    //类的装载是线程安全的,因此这样的写法也是线程安全的
    private static class singleton{
        private static final case7 single = new case7();
    }

    public static case7 getInstance(){
        return singleton.single;
    }

}
2.8 枚举

优点:线程安全的,同时也能防止反序列化重新创建新的对象

enum singleton{
    INSTANCE; //属性
    public void hello(){
        System.out.println("hello");
    }
}

3.总结

1.饿汉式都是线程安全的,它们或多或少都利用了Java的类加载机制,不过不能实现懒加载。

2.懒汉式可实现懒加载,但是有些实现方式要么不是线程安全的要么效率不高。

3.一般比较推荐使用后三种。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值