简单回顾下Java各类单例模式的写法
饿汉式
java
public class SingleClass{
private static final SingleClass INSTANCE = new SingleClass();
private SingleClass(){
}
public SingleClass getSingle(){
return INSTANCE;
}
}
这样在启动时就会创建一个实例,不论是否需要,默认就会创建,因此叫做饿汉式,但这样会浪费内存
懒汉式
java
public class SingleClass{
private static SingleClass instance;
private SingleClass(){
}
public SingleClass getSingle(){
if (instance==null){
instance = new SingleClass();
}
return instance;
}
}
这样在调用时才会创建一个实例,如果不需要,就不会浪费内存了,因此叫做懒汉式
线程安全双重锁校验
java
public class SingleClass{
private static SingleClass instance;
private SingleClass(){
}
public SingleClass getSingle(){
if (instance==null){
synchronized (SingleClass.class) { // 加锁 锁的对象是类对象,其它的线程会等待锁
if (instance==null){
instance = new SingleClass();
}
}
}
return instance;
}
}
这样在调用时才会创建一个实例,若不需要,就不会浪费内存了,这里采用synchronized关键字,锁住整个class对象,线程安全
静态内部类
java
public class SingleClass{
private SingleClass(){
}
//静态内部类 一开始不会加载
public static class Holder{
private static final SingleClass INSTANCE = new SingleClass();
}
//调用方法了才会加载
public static getSingle(){
return Holder.INSTANCE;
}
}
静态内部类 一开始不会加载,调用方法了才会加载,不会浪费内存,多个线程安全
枚举
java
public enum SingleClass {
// 编译器帮你创建:INSTANCE 就是实例
INSTANCE;
// 编译器帮你生成私有构造方法
// 构造方法
SingleClass() {
}
}
原理:枚举只有这里在编译器内部实现相当于 public static final SingleClass INSTANCE = new SingleClass(); 这里创建了一个静态final实例,类加载时就会创建一个实例,线程安全
禁止反射创建多个实例原理:
java
// java.lang.reflect.Constructor 的 newInstance 方法源码:
public T newInstance(Object ... initargs) {
// 关键!如果是枚举,直接抛异常!
if ((clazz.getModifiers() & Modifier.ENUM) != 0) {
throw new IllegalArgumentException("Cannot reflectively create enum objects");
}
}