创建型设计模式之单例模式
Posted 丨Jack_Chen丨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建型设计模式之单例模式相关的知识,希望对你有一定的参考价值。
单例模式
概述
常见单例:
懒汉式:就是需要的才会去实例化,线程不安全。
饿汉式:就是当class文件被加载的时候,初始化,天生线程安全。
比如:ServletContext、ServletContextConfig、ApplicationContext等都是单例形式
优缺点
优点:
1.在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
2.避免对资源的多重占用。
缺点:
1.没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
懒汉式
注意:该方式在多线程中使用存在线程安全问题。
public class Singleton
//需要时才会被实例化
private static Singleton singleton;
private Singleton()
public static Singleton getSingleton()
if (singleton == null)
singleton = new Singleton();
return singleton;
使用synchronized
关键字使方法变成线程同步方法。
这种方法在线程数量较多情况下,如果CPU压力过大,则会导致大批线程阻塞,从而导致程序性能大幅下降。
public class Singleton
//需要时才会被实例化
private static Singleton singleton;
private Singleton()
synchronized public static Singleton getSingleton()
if (singleton == null)
singleton = new Singleton();
return singleton;
public static void main(String[] args)
Singleton sl1 = Singleton.getSingleton();
Singleton sl2 = Singleton.getSingleton();
System.out.println(sl1 == sl2);
使用双重检查锁的的单例模式可进一步提升性能。
public class Singleton
//需要时才会被实例化
private static Singleton singleton;
private Singleton()
public static Singleton getSingleton()
if (singleton == null)
synchronized (Singleton.class)
//检查是否要重新创建实例
if (singleton == null)
singleton = new Singleton();
return singleton;
饿汉式
优点:能保证绝对线程安全、执行效率比较高
缺点:所有对象类加载的时候就实例化
public class Singleton
//当class文件被加载初始化
private static Singleton singleton = new Singleton();
private Singleton()
public static Singleton getSingleton()
return singleton;
public static void main(String[] args)
Singleton singleton1 = Singleton.getSingleton();
Singleton singleton2 = Singleton.getSingleton();
System.out.println(singleton1 == singleton2);
上述是标准写法,还有另外一种写法,利用静态代码块的机制
public class Singleton
//当class文件被加载初始化
private static Singleton singleton;
static
singleton = new Singleton()
private Singleton()
public static Singleton getSingleton()
return singleton;
其他实现方式
静态内部类实现单例
public class Singleton
private Singleton()
if (LazySingleton.INSTANCE != null)
throw new RuntimeException("非法访问");
/**
* 在返回结果前先加载内部类
*/
private static Singleton getInstance()
return LazySingleton.INSTANCE;
/**
* 默认不加载
*/
private static class LazySingleton
private static final Singleton INSTANCE = new Singleton();
ThreadLocal实现线程单例
public class ThreadLocalSingleton
private static final ThreadLocal<ThreadLocalSingleton> threadLocaLInstance =
new ThreadLocal<ThreadLocalSingleton>()
@Override
protected ThreadLocalSingleton initialValue()
return new ThreadLocalSingleton();
;
private ThreadLocalSingleton()
public static ThreadLocalSingleton getInstance()
return threadLocaLInstance.get();
public static void main(String[] args)
ThreadLocalSingleton threadLocalSingleton1 = ThreadLocalSingleton.getInstance();
ThreadLocalSingleton threadLocalSingleton2 = ThreadLocalSingleton.getInstance();
System.out.println(threadLocalSingleton1 == threadLocalSingleton2);
注册式单例模式
注册式单例模式有两种:枚举式单例模式
、容器式单例模式
枚举式单例模式
枚举式单例模式是比较推荐的一种单例模式实现,写法优雅
注意:与饿汉式类似,在类加载时就将所有对象初始化,不适合大量创建单例对象的场景
public enum EnumSingleton
INSTANCE;
public static EnumSingleton getInstance()
return INSTANCE;
public static void main(String[] args)
EnumSingleton instance1 = EnumSingleton.getInstance();
EnumSingleton instance2 = EnumSingleton.getInstance();
System.out.println(instance1 == instance2);
容器式单例模式
容器式单例模式适用于需要大量创建单例对象的场景,便于管理。注意:它是非线程安全的。
public class ContainerSingleton
private ContainerSingleton()
private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();
public static Object getInstance(String className)
Object instance = null;
if (!ioc.containsKey(className))
try
instance = Class.forName(className).newInstance();
ioc.put(className, instance);
catch (Exception e)
e.printStackTrace();
return instance;
else
return ioc.get(className);
public static void main(String[] args)
Object instance1 = ContainerSingleton.getInstance("cn.ybzy.demo.ContainerSingleton");
Object instance2 = ContainerSingleton.getInstance("cn.ybzy.demo.ContainerSingleton");
System.out.println(instance1 == instance2);
单例模式的破坏
反射破坏
private Singleton()
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException
Class<Singleton> singletonClass = Singleton.class;
// 反射强制获取私有构造函数
Constructor<Singleton> declaredConstructor = singletonClass.getDeclaredConstructor(null);
// 强制访问私有构造函数
declaredConstructor.setAccessible(true);
// 暴力调用私有构造函数进行初始化
Singleton singleton1 = declaredConstructor.newInstance();
Singleton singleton2 = declaredConstructor.newInstance();
System.out.println(singleton1 == singleton2);
在私有构造函数中添加限制处理,防止实例多次重复创建。
private Singleton()
if (LazySingleton.INSTANCE != null)
throw new RuntimeException("非法访问");
序列化破坏
public class SeriableSingleton implements Serializable
public final static SeriableSingleton INSTANCE = new SeriableSingleton();
private SeriableSingleton()
public static SeriableSingleton getInstance()
return INSTANCE;
// private Object readResolve() return INSTANCE;
public static void main(String[] args)
SeriableSingleton s1 = SeriableSingleton.getInstance();
SeriableSingleton s2 = null;
FileOutputStream fos = null;
try
fos = new FileOutputStream("SeriableSingleton.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s1);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("SeriableSingleton.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
s2 = (SeriableSingleton) ois.readObject();
ois.close();
System.out.println(s1 == s2);
catch (Exception e)
e.printStackTrace();
关键核心在于ObjectInputStream
中readObject(Class<?> type)
方法调用readObject0
方法中的switch (tc)
判断处理。
private Object readResolve() return INSTANCE;
以上是关于创建型设计模式之单例模式的主要内容,如果未能解决你的问题,请参考以下文章