文章目录
- Java设计模式之单例模式
- 前言
- 一、适用场景
- 二、常见写法
- 1.饿汉式单例
- 2.懒汉式单例
- 方式一
- 方式二
- 方式三
- 方式四
- 3.注册式单例
- 枚举单例
- 容器式单例
- 反序列化单例
- 4.ThreadLocal单例
- 总结
前言
单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。隐藏其所有的构造方法。
一、适用场景
确保任何情况下都绝对只有一个实例。
比如:ServletContext、ServletConfig、ApplicationContext、DBPool
二、常见写法 1.饿汉式单例饿汉式单例模式适用于单例对象比较少的情况。这样可以保证绝对线程安全、执行效率较高,所有对象类加载的时候就实例化。
代码:
public class HungrySingleton {
private static final HungrySingleton instance = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return instance;
}
}
优点:执行效率高、性能高、没有任何锁
缺点:某些情况下,可能会造成内存浪费
代码:
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
优点:节省了内存
缺点:线程不安全
改造:通过synchronized关键字进行加锁
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
public synchronized static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
优点:节省了内存,线程安全
缺点:性能低
改造:双重检查锁
public class LazySingleton {
private volatile static LazySingleton instance; // volatile 防止指令重排序
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton(); // 会出现指令重排序
}
}
}
return instance;
}
}
优点:性能高,线程安全
缺点:可读性差,不够优雅
代码:静态内部类
public class LazySingleton {
private LazySingleton() {
}
public static LazySingleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazySingleton INSTANCE = new LazySingleton();
}
}
优点:写法优雅,利用了Java本身的语法特点,性能高,避免内存浪费
缺点:以上方式都能够被反射破环
将每一个实例都缓存到统一的容器中,使用唯一标识获取实例
枚举单例代码:
public enum EnumSingleton {
INSTANCE;
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
优点:执行效率高、性能高,不能被反射破坏
缺点:某些情况下,可能会造成内存浪费
代码:
public class ContainerSingleton {
private ContainerSingleton() {
}
private static final Map ioc = new ConcurrentHashMap<>();
public static Object getInstance(String className) {
if (ioc.containsKey(className)) {
return ioc.get(className);
}
Object instance = null;
try {
instance = Class.forName(className).newInstance();
ioc.put(className, instance);
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
}
反序列化单例
代码:
public class SerializableSingleton implements Serializable {
private static final SerializableSingleton INSTANCE = new SerializableSingleton();
private SerializableSingleton() {
}
public static SerializableSingleton getInstance() {
return INSTANCE;
}
private Object readResolve() {
return INSTANCE;
}
}
4.ThreadLocal单例
保证线程内部的全局唯一,且天生线程安全
代码:
public class ThreadLocalSingleton {
private static final ThreadLocal INSTANCE = new ThreadLocal() {
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton() {
}
public static ThreadLocalSingleton getInstance() {
return INSTANCE.get();
}
}
总结
单例模式的优点
在内存中只有一个实例,减少了内存开销。
可以避免对资源的多重占用。
设置全局访问点,严格控制访问。
单例模式的缺点
没有接口,扩展困难。
如果要扩展单例对象,只有修改代码,没有其他途径。
注意:
1,私有化构造器
2.保证线程安全
3.延迟加载
4.防止序列化和反序列化破坏单例
5.防止反射攻击单例
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)