如有错误或有补充,以及任何的改进意见,请在评论区留下您的高见,同时文中给出大部分的示例
如果觉得本文写的不错,不妨点个赞,收藏一下,助力博主产生质量更高的作品
概念
单例模式(Singleton Pattern)是软件设计模式的一种,用于确保一个类只有一个实例,并提供一个全局访问点。这种模式通常用于需要频繁创建和销毁同一对象的场景,以减少系统资源的消耗和提高性能。
优缺点
优点:
实例控制:单例模式确保类只有一个实例,可以防止其他对象实例化自己的副本,从而确保所有对象都访问唯一实例。
节约资源:由于系统中只存在一个对象,可以节约系统资源,特别是在需要频繁创建和销毁对象的场景中,可以提高系统的性能。
避免对共享资源的多重占用:单例模式可以避免对共享资源的多重占用,有助于资源的集中管理和控制。
缺点:
扩展困难:由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。如果需要修改单例类的内部逻辑,则必须修改所有使用该单例的地方,不利于代码的模块化和可维护性。
职责过重:单例类通常承载了过多的职责,在一定程度上违背了“单一职责原则”。这会导致代码的复杂性增加,可读性和可维护性降低。
滥用风险:如果滥用单例模式,将一些本应该短生命周期的对象定义为单例,可能会导致内存泄漏和其他问题。例如,将数据库连接池定义为单例,可能会导致连接池溢出或资源耗尽。
状态丢失:在某些情况下,如果实例化的对象长时间不被利用,系统可能会将其视为垃圾回收,导致对象状态的丢失。
使用场景
比如Spring的IOC容器非懒加载的Bean,网页浏览计数等。
实现方式
饿汉式
饿汉式是在类加载时即实例化单例对象的一种方式。在类加载时,饿汉式单例实例就会被创建。这种方式可以确保在程序启动时就能使用单例对象,但是如果在整个应用程序中并不需要使用该单例对象,则会造成资源浪费。
示例
SingletonClass1.java
// 饿汉式
public class SingletonClass1 {
// 创建唯一对象
private static SingletonClass1 instance = new SingletonClass1();
// 避免实例化
private SingletonClass1() {
}
// 获取唯一对象
public static SingletonClass1 getInstance() {
return instance;
}
public void hello () {
System.out.println("This is SingletonClass1");
}
}
Main.java
public class Main {
public static void main(String[] args) {
SingletonClass1.getInstance().hello();
}
}
懒汉式
懒汉式是在需要使用单例对象时才进行实例化的一种方式。在类加载时,懒汉式单例实例并不会被创建,而是在第一次调用时才创建。这种方式可以避免不必要的资源浪费,但在多线程环境下可能会出现问题。在懒汉式实现中,需要将单例的实例化放在一个公共的静态方法中,以确保线程安全。
// 懒汉式
public class SingletonClass2 {
// 初始不加载
private static SingletonClass2 instance = null;
// 避免实例化
private SingletonClass2() {
}
// 获取对象的方法
public static synchronized SingletonClass2 getInstance() {
if (instance == null) {
instance = new SingletonClass2();
}
return instance;
}
public void hello() {
System.out.println("This is SingletonClass2");
}
}
Main.java
public class Main {
public static void main(String[] args) {
SingletonClass2.getInstance().hello();
}
}
以上的懒汉式实现效率较低,每次都要通过synchronized,效率较低
以下是通过双重锁检查机制来使其更加高效的例子:
双重检查锁定(Double-Checked Locking)是一种在多线程环境下使用的同步机制,主要用于实现单例模式。其基本原理是在第一次检查时验证实例是否已经创建,如果已经创建则直接返回实例,不需要进行后续的同步操作。如果实例尚未创建,则进入同步块,在同步块内部进行第二次检查,以确保只有一个线程创建实例。双重检查锁定的目的是在尽量减少同步操作的情况下,保证在多线程环境中只有一个实例被创建,这样可以避免性能下降,同时保证线程安全。需要注意的是,在使用双重检查锁定时,需要使用volatile关键字修饰实例变量,以确保其可见性,避免指令重排序导致的问题。此外,由于不同版本的JVM和编译器对指令重排序的处理方式可能不同,因此在使用双重检查锁定时,需要仔细考虑各种因素,确保其正确性和可靠性。
双重锁检查机制效率更高的原因主要有以下几点:
减少同步锁的调用次数:在懒汉式单例模式中,如果不使用双重锁检查机制,每次调用 getInstance() 方法时都需要获取同步锁,这会导致性能下降。而双重锁检查机制通过第一次检查减少了获取同步锁的次数,只有在实例未创建的情况下才会进入同步块,从而提高了性能。
提升并发度,降低开销:由于双重锁检查机制在第一次检查时只进行了简单的 null 检查,而这个操作是非常快速的,开销也比较小,因此它可以快速地释放同步锁,让其他线程有机会进入同步块,从而提高了并发度。同时也可以降低开销,提高性能。
SingletonClass2Plus.java
// 懒汉式Plus
public class SingletonClass2Plus {
// 初始不加载
private static volatile SingletonClass2Plus instance = null;
// 避免实例化
private SingletonClass2Plus() {
}
public static SingletonClass2Plus getInstance() {
// 第一次检查
if (instance == null) {
synchronized (SingletonClass2Plus.class) {
// 第二次检查
if (instance == null) {
instance = new SingletonClass2Plus();
}
}
}
return instance;
}
public void hello() {
System.out.println("This is SingletonClass2Plus");
}
}
Main.java
public class Main {
public static void main(String[] args) {
SingletonClass2Plus.getInstance().hello();
}
}
原文地址:https://blog.csdn.net/Jiansong_Shen/article/details/135921109
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_65575.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!