GOF23 单例模式

2 篇文章 0 订阅

GOF23

单例模式

保证一个类只有一个实例,并且提供一个访问该实例的全局访问点(获得该类实例的方法)
常见引用场景:

  • windows Task Manager(任务管理器)
  • 项目中,读取配置文件的类 >> 没必要每次使用配置文件数据都 new 一个对象去读取
  • 网站计数器 >> 一般采用单例模式,否则难以同步
  • 应用程序的日志应用 >> 一般采用单例模式,因为共享的日志文件一直处于打开的状态,只能有一个实例去操作,否则内容不好追加
  • 数据库连接池 >> 因为数据库连接是一种数据库资源
  • 操作系统的文件系统 >> 也是最大的单例模式的具体例子,一个操作系统只能有一个文件系统
  • Application(SerlvetContext) 和 Servlet 也是单例
  • Spring 每个默认的 Bean 就是单例,这样做的有点是 方便 ioc 容器管理
  • Spring MVC/Struts1 框架中,控制对象也是单例

优点

  • 由于单例模式只生成一个实例,减少了系统性能的开销,当一个对象的产生需要比较多的资源时,如读取配置文件,产生其他的依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
  • 单例模式可以在系统设置全局的访问点,优化环境共享资源访问

常见的五种单例模式实现方式

  • 主要:
    饿汉式(线程安全, 调用效率高. 但是,不能延时加载)
    懒汉式(线程安全, 调用效率不高, 但是 可以延时加载)
  • 其他
    双重检测锁式(由于jvm 底层内部模型原因,偶尔会出问题,不建议使用)
    静态内部类式(现成安全, 调用效率高, 可以延时加载)
    枚举单例(线程安全, 调用效率高, 不能延时加载)

exmaple: 饿汉式

public class Damo {
    public static void main(String[] args) {
        System.out.println("SingletonDamo.getSingleton() = " + SingletonDamo.getSingleton());
        System.out.println("SingletonDamo.getSingleton() = " + SingletonDamo.getSingleton());
    }
}
class SingletonDamo {
	//类初始化时,立即加载这个对象,加载类时,天然的现成安全!
    private static final SingletonDamo s = new SingletonDamo();
    // 构造方法私有化
    private SingletonDamo() {
    }
    // 对外开放获得实例的静态方法
    public static SingletonDamo getSingleton(){
        return s;
    }
}

在这里插入图片描述

exmaple : 懒汉式 (lazy load)

public class Damo {
    public static void main(String[] args) {
        System.out.println("SingletonDamo.getSingleton() = " + SingletonDamo.getSingleton());
        System.out.println("SingletonDamo.getSingleton() = " + SingletonDamo.getSingleton());
    }
}
class SingletonDamo {
	//类初始化时,不初始化这个对象(延时加载,真正用到时在加载)
    private static SingletonDamo s;
    // 构造方法私有化
    private SingletonDamo() {
    }
    //加上 synchronized 避免多线程时创建多个对象
    public static synchronized SingletonDamo getSingleton(){
        if (s == null)
            s = new SingletonDamo();
        return s;
    }
}

exmaple : 双重检测锁式 (不推荐使用)

public class Damo {
    public static void main(String[] args) {
        System.out.println("SingletonDamo.getSingleton() = " + SingletonDamo.getSingleton());
        System.out.println("SingletonDamo.getSingleton() = " + SingletonDamo.getSingleton());
    }
}
class SingletonDamo {
    private static SingletonDamo s;
    // 构造方法私有化
    private SingletonDamo() {
    }
    //加上 synchronized 避免多线程时创建多个对象
    public static SingletonDamo getSingleton(){
     if (s == null){
         SingletonDamo temp;
         synchronized (SingletonDamo.class){
             temp = s;
             if (temp == null){
                 synchronized (SingletonDamo.class){
                     if (temp == null){
                         temp = new SingletonDamo();
                     }
                 }
                 s = temp;
             }
         }
     }
     return s;
    }
}

exmaple : 静态内部类 (推荐使用)

class SingletonDamo {
    public static SingletonDamo getInstance(){
        return SingletonInstance.
                getSingletonDamo();
    }
    
    private static class SingletonInstance{
        private static final SingletonDamo instance = new SingletonDamo();
        private SingletonInstance() {
        }
        public static SingletonDamo getSingletonDamo(){
            return SingletonInstance.instance;
        }
    }
}

exmaple : 枚举式

public enum SingletonEnum {
    INSTANCE;
   public void show(){
       System.out.println("this = " + this);
   }
}

反射 和 反序列化漏洞

  • 反射
在构造方法中 手动抛出异常
if(instance != null){
	throw new RuntimeException("不能通过反射实例化");
}
  • 反序列化
private Object readResolve() thirows ObjectStreamException(){
	return instance;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值