ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java单例模式Singleton及其七种实现方式

2022-01-03 21:34:45  阅读:159  来源: 互联网

标签:Singleton Java instance 实例 static 单例 public


什么是单例模式

简述

单例模式(Singleton Pattern)是创建型设计模式中最简单且应用最为广泛的设计模式之一,单例模式属于创建型模式,提供了一种对象创建的思路。

使用单例模式时,目标类被要求确保有且仅有一个实例,对于系统任一对目标类的访问,不需要单独实例化类,只需要访问由目标类负责创建的唯一对象实例即可。

特点

  • 使用单例模式的目标类仅有一个实例
  • 由目标类自行创建管理唯一实例
  • 目标类对外提供实例访问方法

应用场景

出现以下场景,可以考虑使用单例模式

  • 某类实例需要被频繁的创建,使用后需要频繁销毁
  • 某类实例化耗时长、占用资源多且使用频繁
  • 某类实例频繁的与数据库或文件交互
  • 某类包含全局状态字段,或在业务逻辑上仅应有单一实例

优缺点

使用单例模式的优点:

  • 减少开销,因为内存中仅有一个实例,减少内存开销,又因为不需要频繁实例化类,减少了性能(时间)开销。
  • 避免对某资源的多重占用,例如对某些文件执行写操作时,单例可以保证对文件同时只有一个写操作。
  • 目标类对外提供唯一实例访问方法,实例可以作为共享资源的被访问。
  • 在某些场景下,某类在逻辑上仅应存在单一实例,使用单例模式可以帮助实现。

单例模式的不足:

  • 违背开闭原则(即对扩展开放,对修改封闭),想要对类进行扩展时,通常只能修改代码。
  • 易违背单一职责原则,即某一功能全部写在一个类中,容易变得冗杂。

单例模式的七种实现方式

懒汉式单例

顾名思义,此种方式实现的单例模式是在目标类要被使用时才创建实例,这种懒加载的好处是在目标类未被实际使用时,不会有实例占据内存空间。

线程不安全方式

此种实现方式线程不安全,在目标类实例还未被创建时,如果有两个线程同时访问了getInstance(),容易产生多个实例,破坏实例的唯一性,不推荐使用。

public class Singleton {
    public static Singleton instance;
    // 使用私有构造方法以避免被外部实例化 确保单例
    private Singleton(){}

    public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

线程安全方式

针对前一种线程不安全的实现方式,可以使用synchronized关键字修饰方法,确保方法同时只能被一个线程访问。虽然此种方式可以保证线程安全同时实现单例,但在单例被创建后,synchronized便失去了本场景下的作用(确保实例的唯一性),且会降低性能开销

public class Singleton {
    public static Singleton instance;
    // 使用私有构造方法以避免被外部实例化 确保单例
    private Singleton(){}
	//使用synchronized保证线程安全
    public synchronized static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

DCL双重检查锁定

前文提及懒汉式为保证线程安全引入synchronized导致性能开销提升,由此衍生出了双重检查锁定(Double Check Lock)的单例实现方式,使用volatile关键字保证可见性避免JVM指令重排引发的问题,同时使用synchronized保证实例创建过程唯一,既保证了懒加载的线程安全,又相较synchronized修饰方法减少了性能开销。

public class DCLSingleton {
    // 注意instance必须要由volatile关键字修饰 目的是保证instance变量的可见性 避免由于指令重排破坏单例的唯一性
    private static volatile DCLSingleton instance;
    
    private DCLSingleton() {}
    
    public static DCLSingleton getInstance() {
        if(instance == null) { //首先判断是否实例化
            //使用synchronized加锁保证实例创建唯一
            synchronized (DCLSingleton.class) {
                if(instance == null) {
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
}

饿汉式单例

饿汉式单例的思路是利用static关键字,使目标类在类加载阶段就创建唯一实例,保证实例在被访问前就已经被创建,确保唯一性,线程安全。

静态变量

public class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

静态代码块

public class Singleton {

    private static Singleton instance;

    private Singleton(){}

    static{
        instance = new Singleton();    
    }
    
    public static Singleton getInstance(){
        return instance;
    }
}

静态内部类

在外部类被装载时,静态内部类不会跟着一起被装载,而是在静态内部类实际被使用的时候(getInstance被调用)才会装载并实例化,所以使用静态内部类实现单例模式具有懒加载的优点,同时JVM在装载类的过程中可以保证线程安全。

public class SingletonStaticClass {

    private SingletonStaticClass(){}
    
    public static final SingletonStaticClass getInstance(){
        return SingletonInstance.instance;
    }

    private static class SingletonInstance{
        private static final SingletonStaticClass instance = new SingletonStaticClass();
    }
}

枚举

枚举实现单例是最安全且写法最简单的,JVM会保证枚举类不能被反射且构造器只能被调用一次,彻底解决了其他单例模式容易被反射和序列化反序列化攻击的问题(见下文),推荐使用。

枚举类单例

public enum EnumSingleton {
    INSTANCE;
    public void method() {
        System.out.println("doSomething");
    }
}

已有类改造

public class EnumSingletonEnhance {
    private EnumSingletonEnhance(){}

    public enum SingletonEnum {
        SINGLETON_ENUM;
        private EnumSingletonEnhance instance = null;
        private SingletonEnum(){
            instance = new EnumSingletonEnhance();
        }
        public EnumSingletonEnhance getinstance(){
            return instance;
        }
    }
    
}

标签:Singleton,Java,instance,实例,static,单例,public
来源: https://blog.csdn.net/MSSPLANET/article/details/122289807

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有