/**
* 单例模式 ~ 懒汉式
*
* @author LTP 2021/11/9
*/
class Singleton_lazy {
private static Singleton_lazy mInstance;
private Singleton_lazy() {
}
public static Singleton_lazy getInstance() {
if (mInstance == null) {
mInstance = new Singleton_lazy();
}
return mInstance;
}
}
2、线程安全的懒汉式
/**
* 单例模式 ~ 线程安全的懒汉式
*
* @author LTP 2021/11/9
*/
class Singleton_lazySync {
private static Singleton_lazySync mInstance;
private Singleton_lazySync() {
}
public static synchronized Singleton_lazySync getInstance() {
if (mInstance == null) {
mInstance = new Singleton_lazySync();
}
return mInstance;
}
}
-
特点:在获取单例的方法上加synchronized关键字保证线程安全,但每次获取都加锁效率比较低
3、双重校验锁DCL(double check lock)
/**
* 单例模式 ~ 双重校验锁DCL(Double check lock)
* 是针对线程安全的懒汉式的优化版本
*
* @author LTP 2021/11/5
*/
public class Singleton_DCL {
/**
* volatile关键字(可见性、防止指令重排、不保证原子性)此处用到了防止指令重排的特性
* 在一个线程分配了mInstance所指向的内存地址,但并未初始化时(发生指令重排),
* 第二个线程在第一个判空的位置会判断mInstance不为空从而直接返回当前mInstance,但事实上mInstance并未初始化而造成错误
* 具体参考:https://blog.csdn.net/llllllkkkkkooooo/article/details/115360630
*/
private static volatile Singleton_DCL mInstance;
private Singleton_DCL() {
}
public static Singleton_DCL getInstance() {
// 第一个判空是减少synchronized加锁,提高效率
if (mInstance == null) {
// 执行位置1
synchronized (Singleton_DCL.class) {
// 第二次判空是防止有多个线程调用getInstance()时都执行在第一次判空之后并阻塞在synchronized之前(执行位置1)
// 从而导致一个线程中初始化后下一个线程继续初始化,从而破坏单例
if (mInstance == null) {
mInstance = new Singleton_DCL();
}
}
}
return mInstance;
}
}
4、饿汉式
/**
* 单例模式 ~ 饿汉式
*
* @author LTP 2021/11/9
*/
class Singleton_hungry {
private static final Singleton_hungry mInstance = new Singleton_hungry();
private Singleton_hungry() {
System.out.println("构造器");
}
public static Singleton_hungry getInstance() {
return mInstance;
}
// 执行顺序:构造器-main
public static void main(String[] args) {
System.out.println("main");
Singleton_hungry instance =Singleton_hungry.getInstance();
}
}
5、静态内部类
/**
* 单例模式 ~ 静态内部类
* 相比较饿汉式的好处是:第一次加载Singleton_staticInnerClass并不会初始化mInstance(调用构造器),
* 只有在调用getInstance()时,才会加载SingletonHolder从而初始化mInstance,
* 参考:https://blog.csdn.net/weixin_30530523/article/details/96640126
*
* @author LTP 2021/11/9
*/
class Singleton_staticInnerClass {
private Singleton_staticInnerClass() {
System.out.println("构造器");
}
public static Singleton_staticInnerClass getInstance() {
return SingletonHolder.mInstance;
}
private static class SingletonHolder {
public static final Singleton_staticInnerClass mInstance = new Singleton_staticInnerClass();
}
// 执行顺序:main-构造器
public static void main(String[] args) {
System.out.println("main");
Singleton_staticInnerClass instance =Singleton_staticInnerClass.getInstance();
}
}
6、枚举
/**
* 枚举,一般不用枚举,可读性差,而且使用枚举会造成内存加大(每个枚举类都会申明成一个静态变量),Android不推荐
*
* @author LTP 2021/11/9
*/
class Singleton_enum {
public static void main(String[] args) {
SingleTon singleTon = SingleTon.INSTANCE;
}
enum SingleTon {
INSTANCE
}
}
-
特点:简单,可读性差,而且Android不推荐使用枚举(加大内存占用)
7、容器类
package com.btpj.design_pattern.singleton;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 单例模式 ~ 容器
* 多种单例类统一管理,在使用时根据key获取对象对应类型的对象。
* 这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,
* 降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度
*
* @author LTP 2021/11/5
*/
public class Singleton_map {
/**
* 使用Map容器类统一管理各单例实例
*/
private static Map<String, Object> mObjMap = new ConcurrentHashMap<>();
private Singleton_map() {
}
/**
* 将实例保存至Map容器
*
* @param key key
* @param instance 实例
*/
public static void addInstance(String key, Object instance) {
if (!mObjMap.containsKey(key)) {
mObjMap.put(key, instance);
}
}
/**
* 根据key获取单例类
*
* @param key key
* @return 获取到的单例类
*/
public static Object getInstance(String key) {
return mObjMap.get(key);
}
}
-
特点:可统一管理多种单例类,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度