概述
上一篇日志中,我们介绍了单例模式的概念和基础的应用
本节中,我们就来介绍一下 java 语言中如何编写单例模式类
只适合单线程环境的单例模式
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance(){
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这是单例模式的最简单实现,private 的构造方法保证了类不会被通过 new 的方式创建,同时,判断 instance 是否为 null 保证了单线程环境下单例模式运行的正确性
但是,正如我们反复强调的,这种方式是非线程安全的,原因在于,当多个线程并发执行,同时进行判断 instance 为 null 的操作,而此时 instance 确实为 null,那么所有的线程都将去创建一个单例的对象,这显然是我们不希望看到的,那么下面我们就来解决这个问题
通过同步锁实现线程安全
正如上面提到的,之所以存在线程安全问题,主要是因为判断 instance 是否为 null 与对象的创建是非原子性的,那么,我们只需要用锁来保证两个操作的原子性即可解决这个问题
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
但是加锁对性能是会造成影响的,在并发环境下,当一个线程运行到 synchronized 处,获取锁进入到 instance 的判断,其他所有的并发线程都必须在该线程执行完 instance 的创建操作后才能够继续执行,而事实上,一旦 instance 被创建,这样的等待都将会是白费的
双重校验锁
双重校验锁对上面的例子进行了优化
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
一旦对象被创建,那么程序将不会去请求获取锁而是直接返回 instance
最简单的线程安全单例模式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() { }
public static Singleton getInstance() {
return instance;
}
}
这段代码看上去非常简单,他会在类首次被加载时创建单例的对象,jvm 会保证单例对象只被创建一次,但是有时我们仅仅是在代码中引用了这个类,或者仅仅调用了这个类中的其他方法,我们并不希望在我们还不需要通过 getInstance 方法获取对象的时候,对象就已经被创建了,这是这种方式的主要问题
静态内部类
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
这种方式解决了上一种方式所存在的问题,仅在 getInstance 方法被调用时,对象才会被创建
使用枚举
public enum SingletonEnum {
BOOM_MAZE_FACTORY(new BoomMazeFactory()),
STANDARD_MAZE_FACTORY(new StandardMazeFactory()),
;
private MazeFactory mazeFactory;
public MazeFactory getMazeFactory() {
return mazeFactory;
}
SingletonEnum(MazeFactory mazeFactory) {
this.mazeFactory = mazeFactory;
}
}
由于枚举在项目中并不会被常常用到,这样的用法就更加难得一见了,而事实上,这才是最推荐的用法
微信公众号
欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤
标签
技术帖
技术分享
java
singleton
设计模式
模式
设计
单例