单例模式
单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。
隐藏其所有的构造方法。
属于创建型模式。
适用场景:
确保任何情况下都绝对只有一个实例。
单例模式的优点:
在内存中只有一个实例,减少了内存开销。
可以避免对资源的多重占用。
设置全局访问点,严格控制访问。
单例模式的缺点:
没有接口,扩展困难。
如果要扩展单例对象,只有修改代码,没有其他途径。
单例模式的常见写法:
1、饿汉式单例
2、懒汉式单例
3、注册式单例
4、ThreadLocal单例
饿汉式单例:
在单例类首次加载时就创建实例
缺点:浪费内存空间
public class HungrySingleton {
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
}
/**
* 饿汉式静态块单例
*/
public class HungryStaticSingleton {
private static final HungryStaticSingleton hungrySingleton;
static {
hungrySingleton = new HungryStaticSingleton();
}
private HungryStaticSingleton() {
}
public static HungryStaticSingleton getInstance() {
return hungrySingleton;
}
}
懒汉式单例:
被外部类调用时才创建实例
懒汉式单例public class LazySimpleSingleton {
private LazySimpleSingleton() {
}
private static LazySimpleSingleton lazy = null;
// 存在性能问题 -> DoubleCheck
public synchronized static LazySimpleSingleton getInstance() {
if (lazy == null) {
lazy = new LazySimpleSingleton();
}
return lazy;
}
}
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton lazy = null;
private LazyDoubleCheckSingleton() {
}
// 适中的方案
// 双重检查锁
public static LazyDoubleCheckSingleton getInstance() {
if (lazy == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazy == null) {
lazy = new LazyDoubleCheckSingleton();
// cpu执行时候会转换成JVM指令执行
// 指令重排序的问题, volatile
//1.分配内存给这个对象
//2.初始化对象
//3.设置lazy指向刚分配的内存地址
//4.初次访问对象
}
}
}
return lazy;
}
}
/**
* 懒汉式单例
* 这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题
* 完美地屏蔽了这两个缺点
* <p>
* 全程没有用到synchronized
* 性能最优的一种写法
*/
public class LazyInnerClassSingleton {
private LazyInnerClassSingleton() {
// 防止使用反射恶意调用,破坏单例
if (LazyHolder.LAZY != null) {
throw new RuntimeException("不允许创建多个实例");
}
}
/**
* 懒汉式单例
* LazyHolder 里面的逻辑需要等到外部方法调用时才执行
* 巧妙利用了内部类的特性
* JVM底层独行逻辑,完美地避免了线程安全阿题
*/
public static final LazyInnerClassSingleton getInstance() {
//在返回结果以前,一定会先加载内部类
return LazyHolder.LAZY;
}
// 默认不加载
private static class LazyHolder {
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
注册式单例:
将每一个实例都缓存到统一的容器中,使用唯一标识获取实例
注册式单例/**
* 枚举单例
*/
public enum EnumSingleton {
// 单例
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
public class ContainerSingleton {
private ContainerSingleton() {
}
private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();
public static Object getInstance(String className) {
synchronized (ioc) {
if (!ioc.containsKey(className)) {
Object obj = null;
try {
obj = Class.forName(className).newInstance();
ioc.put(className, obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
} else {
return ioc.get(className);
}
}
}
}
ThreadLocal单例:
保证线程内部的全局唯一,且天生线程安全
ThreadLocal单例public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> THREAD_LOCAL_INSTANCE =
ThreadLocal.withInitial(ThreadLocalSingleton::new);
private ThreadLocalSingleton() {
}
public static ThreadLocalSingleton getInstance() {
return THREAD_LOCAL_INSTANCE.get();
}
}
学习单例模式的知识重点总结:
1、私有化构造器
2、保证线程安全
3、延迟加载
4、防止序列化和反序列化破坏单例
5、防御反射攻击单例
网友评论