Java设计模式之单例模式
程序员文章站
2022-05-04 17:25:08
...
如果说设计模式也有知名度排名,个人觉得单例模式应该排到第一名。单例模式说简单也简单,说难也难,主要在于不同情况之下应该有不同的选择。
单例特点
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
饿汉模式(线程安全)
public class SingletonDemo {
private static final SingletonDemo singleton = new SingletonDemo();
private SingletonDemo() {
super();
}
public static SingletonDemo getSingleton() {
return singleton;
}
构造函数私有化,这个是常规操作。如果构造函数不私有化,那就可以随时随地 new 一个对象,违背了单例的初衷。
懒汉模式(线程不安全)
public class SingletonDemo {
private static SingletonDemo singleton;
private SingletonDemo() {
super();
}
public static SingletonDemo getSingleton() {
if (singleton == null) {
singleton = new SingletonDemo();
}
return singleton;
}
}
这是教科书上面标准的懒汉模式代码,按需加载。这段代码单线程没有任何问题,多线程就会出现问题,如图所示,会产生两个实例。
懒汉模式(线程安全)
public synchronized static SingletonDemo getSingleton() {
if (singleton == null) {
singleton = new SingletonDemo();
}
return singleton;
}
直接对这个方法加锁,简单粗暴的同步方式,但后续的访问每次都需要竞争锁,开销比较大,这是不必要的开销,就有了新的加锁方式—双重锁。
双重锁模式(线程安全)
public static SingletonDemo getSingleton() {
if (singleton == null) {
synchronized (SingletonDemo.class) {
if (singleton == null) {
singleton = new SingletonDemo();
}
}
}
return singleton;
}
这种方式有效的避免了后续竞争锁的开销,只有第一次初始化的时候竞争锁,对上一段代码优化。
静态内部类(线程安全)
public static SingletonDemo getSingleton() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
private static final SingletonDemo instance = new SingletonDemo();
}
这是利用内部类加载特点实现的线程安全性。
枚举单例(线程安全)
public enum Singleton {
SINGLETON;
public void toDo() {
//TODO
}
}
这是很多大牛都推荐的一种单例实现方式,这个模式单例可以完美避免所有问题,记住是所有问题,不仅仅是线程安全问题。利用了枚举的特性,完美实现了单例。
总结
只追求技术的程序员不是好程序员的,正所谓没有最优的选择,只有最合适的选择,没有场景需要的技术选型,都是耍流氓的。
单例模式这么多,除了枚举,其余都存在一些除了线程安全之外的问题,结合上一篇讲的「Java对象的创建方式」猜测一下会存在哪些问题?
欢迎大家关注我的微信公众号:卡戎