设计模式-单例模式(一)-创新互联

单例模式
  • 一 官方定义
  • 二 单例模式八种方式
    • 2.1 饿汉式(静态常量)
      • 代码案例
      • 案例分析
    • 2.2 饿汉式(静态代码块)
      • 代码案例
      • 案例分析
    • 2.3 懒汉式(线程不安全)
      • 代码案例
      • 案例分析
    • 2.4 懒汉式(线程安全,同步方法)
      • 代码案例
      • 案例分析
    • 2.5 懒汉式(线程不安全,同步代码块)
      • 代码案例
      • 案例分析
    • 2.6 双重检查 (推荐使用)
      • 代码案例
      • 案例分析
        • 优点
        • 可能出现的问题
        • 扩展 - Volatile
    • 2.7 静态内部类 (推荐使用)
      • 代码案例
      • 案例分析
    • 2.8 枚举方式
      • 代码案例
      • 案例分析
    • 三 注意事项
    • 四 单例模式的使用场景

创新互联建站专业网站制作、网站设计,集网站策划、网站设计、网站制作于一体,网站seo、网站优化、网站营销、软文推广等专业人才根据搜索规律编程设计,让网站在运行后,在搜索中有好的表现,专业设计制作为您带来效益的网站!让网站建设为您创造效益。一 官方定义

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)

Spring 中的 bean 默认都是单例模式,每个bean定义只生成一个对象实例,每次 getBean请求获得的都是此实例

二 单例模式八种方式

单例模式的八种实现方式,如下所示

  • 饿汉式(静态常量)
  • 饿汉式(静态代码块)
  • 懒汉式(线程不安全)
  • 懒汉式(线程安全,同步方法)
  • 懒汉式(线程安全,同步代码块)
  • 双重检查
  • 静态内部类
  • 枚举方式
2.1 饿汉式(静态常量) 代码案例
class Singleton {//一:构造器的私有化    防止外部用构造器...
    private Singleton() {}

    //二:类的内部创建对象    final static
    private static final Singleton singleton = new Singleton();

    //三:对外提供公共的静态方法    返回该类唯一的对象实例
    public static Singleton getInstance() {return singleton;
    }
}
案例分析
//案例演示 - 饿汉式
public class SingletonDemo {public static void main(String[] args) {//      方式一:静态常量
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance == instance1); //true
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
}

在这里插入图片描述
通过结果可以发现返回的是同一个对象所以单例模式是实现的。

写法分析
优势: 简单 避免多线程的同步问题
劣势: 没有达到懒加载的效果 内存的浪费

2.2 饿汉式(静态代码块) 代码案例
//方式二:静态代码块的方式
class Singleton {//构造器私有化
    private Singleton() {}

    //类的内部创建对象
    private static final Singleton singleton;

    static {singleton = new Singleton();
    }

    //对外提供公共的静态的方法
    public static Singleton getInstance() {return singleton;
    }
}
案例分析

优势: 简单 避免多线程的同步问题
劣势: 没有达到懒加载的效果 内存的浪费

2.3 懒汉式(线程不安全) 代码案例
class Singleton{//构造器私有化
    private Singleton(){}

    //类的内部提供对象
    private static Singleton singleton;

    //对外提供公共的静态方法的时候,来判断
    public static Singleton getInstance(){if (singleton == null){singleton = new Singleton();
        }

        return singleton;
    }

}
案例分析

优势:起到了懒加载的效果 不会造成内存浪费

在使用到的时候才会创建对象。判断有无对象,有则返回,无创建后再返回

劣势:只能在单线程下使用,多线程情况下线程不安全 不推荐这种方式的
在这里插入图片描述

① 在多线程的情况下,有一个对象进入if判断通过,还没执行到创建对象这一步骤时
② 有另外一个对象也进入了if判断,也通过了。
此时就会出现多个实例,造成线程不安全。

2.4 懒汉式(线程安全,同步方法)

在获取对象的静态方法上添加 synchronized 关键字,实现同步方法。解决线程不安全问题。

代码案例
//加入同步处理  同步方法
class Singleton{//构造器私有化
    private Singleton(){}

    //类的内部提供对象
    private static Singleton singleton;

    //对外提供公共的静态方法的时候,来判断
    public static synchronized Singleton getInstance(){if (singleton == null){singleton = new Singleton();
        }

        return singleton;
    }

}
案例分析

解决了线程安全问题,但是效率太低

每一个线程需求拿实例的时候都要在外面等候另一线程处理完

2.5 懒汉式(线程不安全,同步代码块)

将实例化对象过程放入同步代码块中

代码案例
//加入同步处理 - 同步代码块的方式  不推荐的
class Singleton{//构造器私有化
    private Singleton(){}

    //类的内部提供对象
    private static Singleton singleton;

    //对外提供公共的静态方法的时候,来判断
    public static Singleton getInstance(){if (singleton == null){synchronized (Singleton.class){singleton = new Singleton();
            }

        }

        return singleton;
    }

}
案例分析

不推荐的,解决不了线程的安全问题

这种方式本意是想解决同步方法的问题。但是我们分析一下。在多线程情况下还是有可能创建多个实例的问题。

2.6 双重检查 (推荐使用) 代码案例
class Singleton{private Singleton(){}
    //禁止指令重排
    private static volatile Singleton singleton;
    //加入双重检查机制
    public static Singleton getInstance(){if (singleton == null){synchronized (Singleton.class){if (singleton == null){singleton = new Singleton();
                }
            }
        }

        return singleton;
    }
}
案例分析 优点

线程安全

解决了线程安全问题
① 多线程时,若两个线程同时满足第一层非空判断,等待调用同步代码块。
② 由于添加了synchronized ,当第一个线程进来时,发现Singleton对象为空,进行创建对象并返回。
③ 当另外一个线程调用同步代码块时,进行再次对象非空判断,发现对象已经创建成功。不在执行创建对象流程,返回已有对象

懒加载

使用到对象时才创建,不会造成内存的浪费

效率很高

先进性了singleton 是否为空的判断,singleton 如果不为空直接返回结果。倘若无第一层判空,多线程时每次都要进行synchronized 等待其他线程处理结束,才能进入内部非空判断,效率相对低。

可能出现的问题

我们认为的 new Singleton() 操作

1)分配内存地址 M
2)在内存 M 上初始化Singleton 对象
3)将M的地址赋值给 instance 对象

JVM编译优化后(指令重排)可能的 new Singleton() 操作

1)分配内存地址 M
2)将M的地址赋值给instance变量
3)在内存M上初始化 Singleton 对象

这就有可能出现空指针异常
异常发生过程
在这里插入图片描述
解决方式:关键字 Volatile 来禁止指令重排

扩展 - Volatile

轻量级的同步机制 (低配版) 没有保证原子性
三大特性
保证可见性
其中一个线程修改了主内存共享变量的值,要写回主内存,并要及时通知其他线程可见
没有保证原子性
没法(不能保证)不可分割,完整,要么同时成功,要么同时失败
禁止指令重排
和底层内存屏障相关 避免多线程下出现指令乱序的情况

扩展-线程切换

Java的一条语句对应的cpu指令可能是多条,其中任意一条cpu指令在执行完都可能发生线程切换
count += 1,对应cpu 指令如下:

1)将变量count从内存加载到cpu寄存器
2)寄存器中 +1
3)将结果写入内存(缓存机制写入的可能是cpu而不是内存)
在这里插入图片描述

2.7 静态内部类 (推荐使用) 代码案例
class Singleton{private Singleton(){}

    private static class SingletonInstance{public static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance(){return SingletonInstance.INSTANCE;
    }
}
案例分析

①当Singleton类加载时,静态内部类是不会加载的。
②只有调用getInstance方法用到了SingletonInstance.INSTANCE静态变量时导致SingletonInstance静态内部类进行加载。

不会出现线程安全问题
JVM来帮我们保证了线程的安全性
利用静态内部类的特点,效率也很高,实际开发中推荐使用的

2.8 枚举方式 代码案例
public class EnumDemo {public static void main(String[] args) {//验证其正确性
        Singleton instance = Singleton.INSTANCE;
        Singleton instance1 = Singleton.INSTANCE;
        System.out.println(instance == instance1); //true
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());

    }
}

enum Singleton{INSTANCE; //属性
}
案例分析

不仅可以避免线程安全问题 还可以防止反序列化重新创建对象。推荐使用

三 注意事项
  1. 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
  2. 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new
四 单例模式的使用场景
  • 对于一些需要频繁创建销毁的对象
  • 重量级的对象(创建对象时耗时过多,或者耗费资源过多)
  • 经常使用到的对象
  • 工具类对象
  • 数据源,session。。。。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧

文章标题:设计模式-单例模式(一)-创新互联
网站链接:https://www.cdcxhl.com/article42/djdeec.html

成都网站建设公司_创新互联,为您提供电子商务云服务器建站公司域名注册服务器托管企业网站制作

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

h5响应式网站建设