一、介绍
单例模式是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
二、具体写法
1、懒汉式:线程不安全,没啥特殊嗜好就不要用
/**
* 懒汉式:线程不安全,几乎不可使用
*
* @author zhangxs
**/
public class FirstSingleton {
private static FirstSingleton INSTANCE;
private FirstSingleton() {
}
public static FirstSingleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new FirstSingleton();
}
return INSTANCE;
}
}
2、懒汉式:线程不安全,不推荐使用
/**
* 懒汉式:线程不安全,不推荐使用
*
* @author zhangxs
**/
public class SecondSingleton {
private static SecondSingleton INSTANCE;
private SecondSingleton() {
}
public static SecondSingleton getInstance() {
// 多线程同时进入,这里会导致多个实例的创建,后续改进为双重检查
if (INSTANCE == null) {
synchronized (SecondSingleton.class) {
INSTANCE = new SecondSingleton();
}
}
return INSTANCE;
}
}
3、懒汉式:线程安全,效率较低,可用但不推荐
/**
* 懒汉式:线程安全,效率较低,可用但不推荐,访问线程数量较多的情况下,不能及时得到响应
*
* @author zhangxs
**/
public class ThirdSingleton {
private static ThirdSingleton INSTANCE;
private ThirdSingleton() {
}
public synchronized static ThirdSingleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new ThirdSingleton();
}
return INSTANCE;
}
}
4、静态常量饿汉式:情况允许,可以使用
/**
* 静态常量饿汉式:情况允许,可以使用
*
* @author zhangxs
**/
public class FourthSingleton {
private final static FourthSingleton INSTANCE = new FourthSingleton();
private FourthSingleton() {
}
public static FourthSingleton getInstance() {
return INSTANCE;
}
}
5、静态代码块饿汉式:情况允许,可以使用
/**
* 静态代码块饿汉式:情况允许,可以使用
*
* @author zhangxs
**/
public class FifthSingleton {
private final static FifthSingleton INSTANCE;
static {
INSTANCE = new FifthSingleton();
}
private FifthSingleton() {
}
public static FifthSingleton getInstance() {
return INSTANCE;
}
}
6、静态内部类方式:情况允许,可以使用
/**
* 静态内部类方式:情况允许,可以使用
*
* @author zhangxs
**/
public class SixthSingleton {
private SixthSingleton() {
}
public static SixthSingleton getInstance(){
return SingletonInstance.INSTANCE;
}
/**
* 这个内部类和其内部的INSTANCE都是静态的,JVM类加载时可以保证唯一性
* @author zhangxs
* @date 2021-01-23 11:38
*/
private static class SingletonInstance {
private static final SixthSingleton INSTANCE = new SixthSingleton();
}
}
7、双重线程安全检查,推荐使用,线程安全,延迟加载,效率较高
/**
* 双重线程安全检查,推荐使用,线程安全,延迟加载,效率较高
* 创建一个对象的三个步骤:
* 1、分配内存空间给要创建的对象
* 2、初始化对象时,调用构造器
* 3、实例指向分配的内存地址
* 之所以类中的静态成员变量加了volatile关键字,是为了防止重排序。由对象创建步骤我们可以看到,如果发生了重排序,实例指向分配的内存地址这个操作有可能前置到调用构造器之前,
* 恰好CPU切换到其他线程执行,其他线程如果通过getInstance()中第一个if判断,直接拿到了前面的线程创建了但没有初始化的对象,会出现空指针的情况
* @author zhangxs
**/
public class SeventhSingleton {
private volatile static SeventhSingleton INSTANCE;
private SeventhSingleton() {
}
public static SeventhSingleton getInstance(){
if(INSTANCE == null){
synchronized (SeventhSingleton.class){
if(INSTANCE == null){
INSTANCE = new SeventhSingleton();
}
}
}
return INSTANCE;
}
}
8、枚举懒加载,推荐使用,最好的单例实现方式
/**
* 枚举懒加载,推荐使用,最好的单例实现方式
* 这种方式可以防止反射调用私有构造器来破坏单例,也可以避免反序列化破坏单例
* @author zhangxs
**/
public enum EighthSingleton {
/** 对象实例 */
INSTANCE;
private String name;
public void doSomething() {
System.out.println(name + " is doing something now...");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
三、总结
没有更多特殊的要求,用枚举实现单例就完了,顶多双重线程安全检查的方式,其他的方式知道即可。