单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建
。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式具有典型的三个特点:
- 只有一个实例。
- 自我实例化。
- 提供全局访问点。
1、饿汉模式
在类加载的时候就创建实例,饿汉模式是线程安全
的
但是如果不使用,也产生了不需要的实例
public class Singleton {
//1、持有自己类型的属性
private static Singleton instance=new Singleton();
//2、私有的构造器
private Singleton() {
}
//3、提供对外获取实例的方法
public static Singleton getInstance(){
return instance;
}
}
2、懒汉模式
懒汉模式:在调用getInstance方法时,实例才被创建
2.1、存在多线程下会产生多个实例!!!!!!,这与单例模式的初衷相悖
public class Singleton {
//1、持有自己类型的属性
private static Singleton instance;
//2、私有的构造器
private Singleton() {
}
//3、提供对外获取实例的方法
public static Singleton getInstance(){
if(instance == null){
instance=new Singleton();
}
return instance;
}
}
2.2、改进一、对 getInstance()方法加synchronized关键字修饰
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
public class Singleton {
//1、持有自己类型的属性
private static Singleton instance;
//2、私有的构造器
private Singleton() {
}
//3、提供对外获取实例的方法
synchronized public static Singleton getInstance(){
if(instance == null){
instance=new Singleton();
}
return instance;
}
}
2.3、改进二、double-checked locking、双检锁、DCL
大多数多线程结合单例模式的解决方案
但是还是存在小概率的线程安全问题,是因为有指令重排序的存在。解决办法volatile关键字修饰属性。
public class Singleton {
//1、持有自己类型的属性
private static Singleton instance;
//2、私有的构造器
private Singleton() {
}
//3、提供对外获取实例的方法
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) { // 在synchronized 前后进行判断
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
2.4、改进三、使用静态内部类
是否 Lazy 初始化:是
是否多线程安全:是
public class Singleton {
//静态内部类
private static class SingletonHolder {
private static Singleton INSTANCE = new Singleton();
}
//私有的构造器
private Singleton (){
}
//提供对外获取实例的方法
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
3、使用枚举
是否 Lazy 初始化:否
是否多线程安全:是
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
总结
饿汉模式是线程安全的,但是类加载时就初始化,浪费内存。
懒汉模式可以使用DCL双检索方式、静态内部类。
如果涉及到反序列化创建对象时,可以使用枚举。
参考:
https://www.runoob.com/design-pattern/singleton-pattern.html