设计模式-第三课-单例模式

单例模式是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。常用的几种单例模式包括饿汉式、懒汉式、双重检验锁和静态内部类。

  • 饿汉式单例模式

饿汉式单例模式是在类加载时就创建了实例,因此在多线程环境下也是安全的。示例代码如下:

public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}
  • 懒汉式单例模式

懒汉式单例模式是在第一次使用时才创建实例,因此可能会存在线程安全问题。为了解决这个问题,可以使用双重检验锁或者静态内部类的方式。示例代码如下:

 
// 双重检验锁
public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

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

// 静态内部类
public class Singleton {
    private Singleton() {}

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

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

  • 枚举单例模式

枚举单例模式是在Java 5中新增的一种单例模式,它是线程安全的,并且可以防止反射和序列化等攻击。示例代码如下:

public enum Singleton {
    INSTANCE;

    public void doSomething() {
        // do something
    }
}

在这些单例模式中,实际开发中,最常用的单例模式是饿汉式单例和懒汉式双重检查锁单例。

        饿汉式单例的优点是实现简单,线程安全,且在使用时没有额外的同步开销,因此在需要在多个线程中频繁调用单例对象的情况下,是一个不错的选择。但是其缺点是会在类加载时就创建对象,占用内存,可能会影响程序的性能和资源利用。

        懒汉式双重检查锁单例则通过延迟初始化的方式来实现懒加载,只有在使用时才会创建单例对象,因此不会占用过多的内存资源。同时又通过双重检查锁的方式保证了线程安全性。但是其实现比较复杂,需要注意线程安全的细节,因此在实现时需要更加小心谨慎。

        因此,选择哪种单例模式取决于具体的场景和需求。如果在需要在多个线程中频繁调用单例对象的情况下,可以考虑使用饿汉式单例;如果需要延迟初始化并且要保证线程安全,可以考虑使用懒汉式双重检查锁单例。

枚举的单例模式天生就是线程安全的,因为:

  1. 枚举类型在JVM中只会被实例化一次,因此在多线程环境下也是线程安全的。

  2. 枚举类型在Java语言中有特殊的处理机制:枚举类型的实例在类加载时就会被创建,因此在多线程环境下也是线程安全的。

        底层的实现方式是,在Java编译器编译枚举类型时,会自动将其转换为一个继承自Enum类的final类。而枚举类型的成员在类加载时就被实例化,且实例化后无法被修改,因此枚举类型本身就具有线程安全性。

下面是一个简单的枚举类型的示例代码:

public enum Season {
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER;
}

经过编译器编译后,这个枚举类型的底层代码类似于下面的代码:

final class Season extends Enum<Season> {
    public static final Season SPRING = new Season();
    public static final Season SUMMER = new Season();
    public static final Season AUTUMN = new Season();
    public static final Season WINTER = new Season();

    private Season() {
        super(name(), ordinal());
    }

    public static Season[] values() {
        return (Season[]) $VALUES.clone();
    }

    public static Season valueOf(String name) {
        return (Season) Enum.valueOf(Season.class, name);
    }

    private static final Season[] $VALUES = { SPRING, SUMMER, AUTUMN, WINTER };
}

        在这个底层代码中,Season继承自Enum类,并包含了4个常量:SPRING、SUMMER、AUTUMN、WINTER。这些常量在类加载时被实例化,因此它们的实例在JVM中只会被实例化一次,从而保证了枚举类型的线程安全性。

        由于枚举类型的特殊处理机制,枚举单例模式在Java中被广泛使用,它不仅具有线程安全性,还可以防止反射和序列化等攻击。

        常见的开发框架中也会有不少地方有单例模式的出现。

  1. Spring 框架中,Bean 对象默认为单例模式,每个 Bean 只会创建一次,以后每次使用都会返回同一个对象。例如:
@Service
public class MyService {
    // 单例模式
}

 MyBatis 框架中,SqlSessionFactory 对象是单例模式,它负责创建 SqlSession 对象。例如:

public class MybatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        // ...
        return sqlSessionFactoryBean;
    }
}

Log4j 日志框架中,LogManager 对象是单例模式,它管理所有的 Logger 对象。例如:

public class LogManager {
    private static final Logger LOGGER = Logger.getLogger(LogManager.class);
    // ...
}

JDK 中,Runtime 类是单 例模式,它表示应用程序的运行时环境。例如:

Runtime runtime = Runtime.getRuntime();

        总之,单例模式在各种框架和库中广泛使用,它可以确保一个类只有一个实例,并且提供了一种方便的全局访问方式,从而提高了程序的性能和可维护性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心若自由何处是束缚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值