单例模式
单例模式是java的创建型模式之一。
定义:单例模式能够防止频繁创建和销毁全局使用的类实例的问题,该模式确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
特点:
- 1、单例类只能有一个实例;
- 2、单例类只能自己创建自己的唯一实例;
- 3、保证其他类对象能访问该实例。
单例模式的实现方式有多种:懒汉式、饿汉式、双重校验锁、静态内部类、枚举。
下面依次介绍单例模式的不同方式实现:
懒汉式
懒汉式即创建实例之后懒得初始化,等到方法使用时再初始化。
优点:第一次调用时才加载,防止内存浪费;
缺点:加锁影响效率
public class Singleton {
//static关键字确保在所有调用中共享同一实例
private static Singleton instance;
//其他类无法创建本类实例
private Singleton (){}
//保证能全局访问,去掉锁就变成线程不安全的懒汉式
public static synchronized Singleton getInstance() {
//实例在第一次请求时才创建(延迟加载)
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式
优缺点与懒汉式相反:不需要加锁,效率高;类加载时就创建单例实例,浪费内存。
public class Singleton {
//在类加载时就创建单例实例
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
双重检验锁
优点:使用双锁机制,保证线程安全时还能保持高性能。
原理:使用volatile关键字防止指令重排序导致的线程安全问题,同时只在第一次初始化实例的时候加synchronized锁,后续调用不需要加锁,相比懒汉式每次调用实例都加锁大大提高了效率。
public class Singleton {
// volatile 关键字确保实例的可见性和有序性
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) { //第一次检查
synchronized (Singleton.class) {
if (singleton == null) { //第二次检查
//延迟加载
singleton = new Singleton();
}
}
}
return singleton;
}
}
静态内部类
这种方式只适用于静态域的情况,能达到双检锁方式一样的功效。
原理:只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。由于静态内部类只有第一次使用时才会被加载(类加载机制),也就无需检查实例。
public class Singleton {
// 静态内部类,只有在第一次使用时才会被加载
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
// 提供全局访问点,通过内部类加载实现懒加载和线程安全
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举
最简洁,自动支持序列化机制,绝对防止多次实例化。
原理:枚举类型的每一个实例都是 public static final 的,枚举类型的构造方法在类加载时被调用,并且每个枚举常量只被初始化一次。
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}