文章目录
单例模式介绍
- 单例模式介绍
- 单例模式的7种写法
- 0. 静态类的使用
- 懒汉模式 线程不安全的写法
- 线程安全的懒汉模式 方法上全局加锁
- 饿汉式单例模式
- 单例模式 内部类的写法 线程安全 (推荐)
- 双重检查的单例模式 (推荐)
- cas 加 AtomicReference 实现安全的单例
- 枚举实现单例模式
系统中只允许创建一个对象.
- 数据库的连接池.
- spring的单例bean
- 配置类等
public class Singleton00 {
/**
* 系统第一次运行的时候, 直接初始化该类 , 不需要维持任何状态, 仅仅需要全局访问.
*/
public static Map cache = new ConcurrentHashMap();
}
系统第一次运行的时候, 直接初始化该类 , 不需要维持任何状态, 仅仅需要全局访问
懒汉模式 线程不安全的写法public class Singleton01 {
private static Singleton01 instance;
// 构造方法私有化, 防止外部创建对象
private Singleton01() {
}
public static Singleton01 getInstance() {
// 多线程的情况下会创建多个对象
if (instance != null) {
return instance;
}
return new Singleton01();
}
}
线程安全的懒汉模式 方法上全局加锁
public class Singleton02 {
private static Singleton02 instance;
private Singleton02() {
}
// 全局加锁 线程安全但 性能差.
public static synchronized Singleton02 getInstance() {
if (null != instance) return instance;
return new Singleton02();
}
}
饿汉式单例模式
public class Singleton03 {
// 程序一运行就加载单例对象, 虽然线程安全, 但会导致内存暴增
private static Singleton03 instance = new Singleton03();
private Singleton03() {
}
public static Singleton03 getInstance() {
return instance;
}
}
单例模式 内部类的写法 线程安全 (推荐)
public class Singleton04 {
private static class SingletonHolder {
// 一个类的构造方法在多线程环境下是线程安全的 jvm可以保证多线程并发访问的准确性
private static Singleton04 instance = new Singleton04();
}
private Singleton04() {
}
public static Singleton04 getInstance() {
return SingletonHolder.instance;
}
}
双重检查的单例模式 (推荐)
教程中 volatile 没有加上. 此处volatile 保证可见性, 并且保证创建对象的时候 禁止指令重排.
public class Singleton05 {
private volatile static Singleton05 instance;
private Singleton05() {
}
public static Singleton05 getInstance() {
if (null!=instance) return instance;
synchronized (Singleton05.class) {
if (null == instance) {
instance = new Singleton05();
}
}
return instance;
}
}
cas 加 AtomicReference 实现安全的单例
AtomicReference 可以封装引⽤⼀个V实例,⽀持并发访问如上的单例⽅式就是使⽤了这样的⼀个特点。 CAS有⼀个缺点就是盲等,如果⼀直没有获取到对象将会处于死循环中
public class Singleton06 {
private static final AtomicReference INSTANCE = new AtomicReference();
private static Singleton06 instance;
private Singleton06() {
}
public static final Singleton06 getInstance() {
// CAS有⼀个缺点就是盲等,如果⼀直没有获取到对象将会处于死循环中
for (; ; ) {
Singleton06 instance = INSTANCE.get();
if (instance!=null) return instance;
// 只有是null 的时候 才创建对象 .
INSTANCE.compareAndSet(null, new Singleton06());
return INSTANCE.get();
}
}
}
枚举实现单例模式
/**
* 类名称:Singleton07
* 枚举实现单例模式 此种⽅式在存在继承场景下是不可⽤的
* 创建时间:2022/3/19 17:48
*/
public enum Singleton07 {
INSTANCE;
public void test() {
System.out.println("hi singleton");
}
}
测试类
import com.thc.design.Singleton03;
import com.thc.design.Singleton04;
import com.thc.design.Singleton05;
import com.thc.design.Singleton07;
import org.junit.Test;
/**
* 类名称:SingletonTest
* 创建时间:2022/3/19 17:27
*/
public class SingletonTest {
@Test
public void test_Singleton03() {
Singleton03 instance1 = Singleton03.getInstance();
Singleton03 instance2 = Singleton03.getInstance();
System.out.println(instance1); // Singleton03@722c41f4
System.out.println(instance2); // Singleton03@722c41f4
}
@Test
public void test_Singleton04() {
Singleton04 instance1 = Singleton04.getInstance();
Singleton04 instance2 = Singleton04.getInstance();
System.out.println(instance1); // Singleton04@722c41f4
System.out.println(instance2); // Singleton04@722c41f4
}
@Test
public void test_Singleton05() {
Singleton05 instance1 = Singleton05.getInstance();
Singleton05 instance2 = Singleton05.getInstance();
System.out.println(instance1); // Singleton05@722c41f4
System.out.println(instance2); // Singleton05@722c41f4
}
@Test
public void test_Singleton07() {
Singleton07.INSTANCE.test(); //hi singleton
}
}