单例模式
饿汉式
普通饿汉式
public class HungrySingleton {
// 不加final 可能会通过反射机制覆盖
private static final HungrySingleton HUNGRY_SINGLETON = new HungrySingleton();
// 1. 构造方法私有
private HungrySingleton() {
}
// 2. 全局访问
public static HungrySingleton getInstance() {
return HUNGRY_SINGLETON;
}
}
静态代码块
public class HungryStaticSingleton {
private static final HungryStaticSingleton HUNGRY_SINGLETON;
static {
HUNGRY_SINGLETON = new HungryStaticSingleton();
}
// 1. 构造方法私有
private HungryStaticSingleton() {
}
// 2. 全局访问
public static HungryStaticSingleton getInstance() {
return HUNGRY_SINGLETON;
}
}
序列化单例
public class SerializableSingleton implements Serializable {
public final static SerializableSingleton INSTANCE = new SerializableSingleton();
public static SerializableSingleton getInstance() {
return INSTANCE;
}
// 序列化破坏单例的解决方式
// 重写readResolve 方法,只不过是覆盖了反序列化出来的对象
// 还是创建了两次,发生在JVM层面,相对来说比较安全
// 之前反序列化出来的对象会被GC回收
private Object readResolve() {
return INSTANCE;
}
}
readResolve()
public class SerializableSingletonTest {
public static void main(String[] args) {
SerializableSingleton s1 = null;
SerializableSingleton s2 = SerializableSingleton.getInstance();
FileOutputStream fos = null;
try {
fos = new FileOutputStream("SerializableSingleton.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("SerializableSingleton.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (SerializableSingleton) ois.readObject();
ois.close();
System.out.println(s1 == s2);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
懒汉式
存在线程问题的懒汉式
public class LazySingleton {
private static LazySingleton lazySingleton = null;
// 构造方法私有化
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
方法加synchronized
的懒汉式(类锁)
public class LazySimpleSingleton {
private static LazySimpleSingleton lazySimpleSingleton = null;
// 构造方法私有化
private LazySimpleSingleton() {
}
// synchronized 性能问题
public synchronized static LazySimpleSingleton getInstance() {
if (lazySimpleSingleton == null) {
lazySimpleSingleton = new LazySimpleSingleton();
}
return lazySimpleSingleton;
}
}
synchronized
加载 static
修饰的方法时,会变成类锁。
类锁 是锁住整个类,当有多个线程来访问getInstance()
时候将会被阻塞,直到拥有这个类锁的对象被销毁或者主动释放了类锁。
synchronized
修饰普通方法,即为 对象锁
多个线程访问同一个对象实例的这个方法时,是会同步的,并且只有一个线程执行完,另一个线程才会执行
双重锁检查
改良后的
对象锁 --> 类锁
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
// 构造方法私有化
private LazyDoubleCheckSingleton() {
}
// 双重检查锁
public synchronized static LazyDoubleCheckSingleton getInstance() {
if (lazyDoubleCheckSingleton == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazyDoubleCheckSingleton == null) {
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
// CPU执行时候会转换成JVM指令
// 2 3 会有指令重排序
// 1. 分配内存给这个对象
// 2. 初始化对象
// 3. 将初始化好的对象和内存地址建立关联, 赋值
// 4. 用户初次访问
}
}
}
return lazyDoubleCheckSingleton;
}
}
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton()
这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。
- 给
lazyDoubleCheckSingleton
分配内存 - 调用
LazyDoubleCheckSingleton
的构造函数来初始化成员变量 - 将
lazyDoubleCheckSingleton
对象指向分配的内存空间(执行完这步lazyDoubleCheckSingleton
就为非 null 了)
volatile
起到禁止指令重排的作用,在它赋值完成之前,就不会调用读操作(lazyDoubleCheckSingleton
== null)
静态内部类
静态内部类不会在单例加载时加载,当调用 getInstance()
方法时才会进行加载,达到类似懒汉式效果,并且也是线程安全的。
// 全程没有用到synchronized关键字
// 内部类比外部类优先加载
// 性能最优的一种写法
public class LazyInnerClassSingleton {
// 虽然构造方法私有,但是逃不过构造方法
private LazyInnerClassSingleton() {
if (LazyHolder.LAZY != null) {
throw new RuntimeException("不允许构建多个实例");
}
}
// 懒汉式单例
// LazyHolder 里面的逻辑需要等到外部方法调用时才执行
// 巧妙利用了内部类的特性
// JVM底层执行逻辑,完美地避免了线程安全问题
public static final LazyInnerClassSingleton getInstance() {
return LazyHolder.LAZY;
}
private static class LazyHolder {
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
破坏单例
public class LazyInnerClassSingletonTest {
public static void main(String[] args) {
try {
// 破坏了单例
Class<?> clazz = LazyInnerClassSingleton.class;
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(null);
// 授权 强制访问
declaredConstructor.setAccessible(true);
Object o1 = declaredConstructor.newInstance();
Object o2 = LazyInnerClassSingleton.getInstance();
System.out.println(o1 == o2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
枚举
// 懒汉式线程安全
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
能防止反序列化时重新创建新的对象
EnumSingleton
的定义利用的enum是一种特殊的class。代码中的第一行INSTANCE
会被编译器编译为EnumSingleton
本身的一个对象.当第一次访问EnumSingleton.INSTANCE
时会创建该对象,并且enum变量的创建是线程安全的.
ThreadLocal
ThreadLocal<>
为每一个线程提供一个独立的变量副本
public class ThreadLocalSingleton {
private ThreadLocalSingleton() {
}
private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance =
ThreadLocal.withInitial(() -> new ThreadLocalSingleton());
private static ThreadLocalSingleton getInstance() {
return threadLocalInstance.get();
}
}
容器化单例
public class ContainerSingleton {
private ContainerSingleton() {
}
private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();
public static Object getBean(String className) {
if (!ioc.containsKey(className)) {
Object obj = null;
try {
obj = Class.forName(className).newInstance();
ioc.put(className, obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
return ioc.get(className);
}
}