一、什么是Singleton?
1. 简介
Singleton: 在 java 中即指单例设计模式,它是软件开发中最常用的设计模式之一。
单例模式,单:唯一; 例:实例
单例设计模式,即某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式。
例如:java的代表 JVM 运行环境的Runtime类。
2. 要点
(1) 某个类只能有一个实例: 意味着构造器必须私有化
(2)它必须自行创建这个实例: 用含有一个该类的静态变量来保存这个唯一的实例
(3)它必须自行向整个系统提供这个实例:
对外提供获取该实例对象的方式:
直接暴露;
用静态变量的get方法获取。
3. 饿汉式构造
在类初始化时直接创建对象,不存在线程安全问题
(1)直接实例化饿汉式(简洁直观)
/**
* @author Harbour
* @create 2020-11-10 9:35
*
* (1)构造器私有化
* (2)用静态变量存储此实例
* (3)向外提供这个实例,用public修饰
* (4)强调这是一个单例,可以用final修改,大写
*/
public class Singleton01 {
// 1. 直接实例化的方式
public static final Singleton01 INSTANCE = new Singleton01();
private Singleton01() {};
}
(2)枚举式(最简洁)
/**
* @author Harbour
* @create 2020-11-10 9:42
* (1) 枚举类: 表示该类型的对象只有有限的几个
* (2) 我们可以给他限定为1个,即成了单例模式
* (3) 枚举类的构造器都是私有化的
*/
public enum Singleton02 {
// 2. 直接枚举类创建
INSTANCE
}
(3)静态代码块饿汉式(适合复杂实例化)
package singleton;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Properties;
/**
* @author Harbour
* @create 2020-11-10 9:46
* (1) 适用于复杂类型的单例,比如需要从外接加载必要的信息
*/
public class Singleton03 {
// 3. 静态代码块式的构造
public static final Singleton03 INSTANCE;
private String info;
static {
try {
Properties pro = new Properties();
pro.load(Singleton03.class.getClassLoader().getResourceAsStream("single.properties"));
INSTANCE = new Singleton03(pro.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Singleton03(String info) {
this.info = info;
};
}
4. 懒汉式构造
延迟创建对象,存在线程安全问题
(1)线程不安全(适用于单线程)
package singleton;
/**
* @author Harbour
* @create 2020-11-10 10:46
* 第一中懒汉式构造方式,存在线程安全问题,可能创建多个实例
*/
public class Singleton04 {
private static Singleton04 instance;
private Singleton04 () {};
public Singleton04 getInstance() {
if (instance != null) {
try {
/* 第一个线程等待了1000毫秒,然后继续创建实例
第二个线程在这1000毫秒之内进来了,然后也创建了实例
于是出现了两个实例,导致线程不安全
*/
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton04();
}
return instance;
}
}
(2)线程安全(适用于多线程)
package singleton;
/**
* @author Harbour
* @create 2020-11-10 10:46
* 第二种懒汉式构造方式,不存在线程安全问题
*/
public class Singleton05 {
private static Singleton05 instance;
private Singleton05() {};
public Singleton05 getInstance() {
// 外层判断是为了提高运行效率,没必要每次都执行内部同步代码块
if (instance != null) {
// 内层同步代码块,保证第一次创建时不会存在线程安全问题
synchronized (Singleton05.class) {
if (instance != null) {
instance = new Singleton05();
}
}
}
return instance;
}
}
(3)静态内部类形式(适用于多线程)
package singleton;
/**
* @author Harbour
* @create 2020-11-10 10:46
* 第三种懒汉式构造方式,适用多线程
* (1)在内部类被加载和初始化时,才创建INSTANCE实例对象
* (2)静态内部类不会自动随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的
* (3)因为是在内部类加载和初始化时,创建的,因此是线程安全的
*/
public class Singleton06 {
private Singleton06() {};
private static class Inner{
private static final Singleton06 INSTANCE = new Singleton06();
}
public static Singleton06 getInstance () {
return Inner.INSTANCE;
}
}