一、什么是单例模式
一个类有且仅有一个实例,并且自行实例化向整个系统提供。
二、特点
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
三、应用场景
控制实例数目,节省系统资源的时候,例如线程池、缓存、日志对象等,或用于计数。
四、实现方式
- 饿汉式
//饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
//ps: 类加载时就创建对象,所以会导致类加载变慢。若不使用这个实例,则相当于浪费内存。
// 也正因为类加载时创建,保证了线程安全
//饿汉式-第二种写法
public class Singleton {
private Singleton instance = null;
static{
instance=new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
//ps: 与第一种实现过程一致
2.懒汉式
//懒汉式-基础版
public class Singleton {
private static Singleton instance;
private Singleton (){} //私有构造函数,无法从外部获取
public static Singleton getInstance() { //静态实例,创建对象
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//ps: 实现了类加载时不创建实例,而是在调用时创建实例,有效的避免了内存的浪费。
// 但是,此种方式不能保证线程安全,所以仅适用于单线程
//懒汉式-加锁版
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//ps: 在基础版的基础上实现了线程安全,但在方法上加锁会影响效率。即:如果频繁的调用getInstance()方法,会频繁的加锁。
//懒汉式-加锁版2
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
//ps: 摒弃了同步方法改为同步实例化代码块,虽然效率提高了,但又出现了线程安全问题。
//懒汉式-加锁版2优化:双重校验
public class Singleton {
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;
}
}
//ps: 进行两次实例判空操作,实现线程安全。采用volatile关键字,volatile可以保证即使Java虚拟机对代码执行了指令重排序,也会保证它的正确性。
// 推荐使用
3.静态内部类实现
//静态内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
//ps: 这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。
// 这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
4.枚举实现
public class EnumSingleton{
private EnumSingleton(){}
public static EnumSingleton getInstance(){
return Singleton.INSTANCE.getInstance();
}
private static enum Singleton{
INSTANCE;
private EnumSingleton singleton;
//JVM会保证此方法绝对只调用一次
private Singleton(){
singleton = new EnumSingleton();
}
public EnumSingleton getInstance(){
return singleton;
}
}
}
//ps: 简洁,自动支持序列化机制,绝对防止多次实例化。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象