单例模式
单例模式允许一个应用程序在每一个 JVM 实例中有且只有一个类的实例对象。
特征
- 一个JVM 实例内只有一个类的实例对象。
饿汉模式
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
// private constructor
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return instance;
}
}
懒汉模式
public class LazySingleton {
private static volatile LazySingleton instance = null;
// private constructor
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
// Double check
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
双重懒加载
使用volatile关键字的目的不是保证可见性(synchronized已经保证了可见性),而是为了保证顺序性。具体来说,INSTANCE = new Singleton()不是原子操作,实际上被拆分为了三步:1) 分配内存;2) 初始化对象;3) 将INSTANCE指向分配的对象内存地址。 如果没有volatile,可能会发生指令重排,使得INSTANCE先指向内存地址,而对象尚未初始化,其它线程直接使用INSTANCE引用进行对象操作时出错。
双重空检查:防止两个线程,实例化两个对象。一个线程T1 读到对象为空,另一个线程T2读到对象也为空,T1 加锁实例化,T2 加锁实例化。这样就是两个实例了。
静态代码块
public class StaticBlockSingleton {
private static final StaticBlockSingleton INSTANCE;
static {
try {
INSTANCE = new StaticBlockSingleton();
} catch (Exception e) {
throw new RuntimeException("Uffff, i was not expecting this!", e);
}
}
public static StaticBlockSingleton getInstance() {
return INSTANCE;
}
private StaticBlockSingleton() {
// ...
}
}
静态内部类
推荐
public class BillPughSingleton {
private BillPughSingleton() {
}
private static class LazyHolder {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return LazyHolder.INSTANCE;
}
}
枚举
public enum EnumSingleton {
INSTANCE;
public void someMethod(String param) {
// some class member
}
// 该方法非必须,只是为了保证与其它方案一样使用静态方法得到实例
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
序列化&反序列化问题
public class DemoSingleton implements Serializable {
private static final long serialVersionUID = 1L;
private DemoSingleton() {
// private constructor
}
private static class DemoSingletonHolder {
public static final DemoSingleton INSTANCE = new DemoSingleton();
}
public static DemoSingleton getInstance() {
return DemoSingletonHolder.INSTANCE;
}
protected Object readResolve() {
return getInstance();
}
}
场景
- java.lang.Runtime.getRuntime();
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
}
- MyBatis 中的 VFS (Virtual File System) 实例
public abstract class VFS {
private static class VFSHolder {
// 单例模式, 全局唯一 VFS 对象
static final VFS INSTANCE = createVFS();
static VFS createVFS() {
// Try the user implementations first, then the built-ins
// 优先使用用户自义的 VFS 现, 如采没自定义 VFS 实现,则使用 MyBatis 提供的 VFS 实现
List<Class<? extends VFS>> impls = new ArrayList<>();
impls.addAll(USER_IMPLEMENTATIONS);
impls.addAll(Arrays.asList((Class<? extends VFS>[]) IMPLEMENTATIONS));
// Try each implementation class until a valid one is found
// 造历 impls 集合,依次实例化 VFS 对象并检测 VFS 对象是否有效,一旦得到有效的 VFS 对象,则结束循环
VFS vfs = null;
for (int i = 0; vfs == null || !vfs.isValid(); i++) {
Class<? extends VFS> impl = impls.get(i);
// 通过类的构造方法创建VFS实例
vfs = impl.getDeclaredConstructor().newInstance();
if (!vfs.isValid()) {
if (log.isDebugEnabled()) {
log.debug("VFS implementation " + impl.getName() +
" is not valid in this environment.");
}
}
return vfs;
}
}
/**
* Get the singleton {@link VFS} instance. If no {@link VFS} implementation can be found for the
* current environment, then this method returns null.
*/
public static VFS getInstance() {
return VFSHolder.INSTANCE;
}
}
VFS 表示虚件系统 Virtual File System 来查找指定路径下的资源。资源比如: jar 或者 class 文件
网友评论