饱汉模式
import java.util.Objects;
/**
* 线程安全的单例模式(饱汉)
*
* @author Chris
* @date 2020/02/28 23:37
* @since 1.0.0
*/
public class Singleton1 {
private static volatile Singleton1 ourInstance;
/** DCL 双重检查锁机制 */
public static Singleton1 getInstance() {
if (Objects.isNull(ourInstance)) {
synchronized (Singleton1.class) {
if (Objects.isNull(ourInstance)) {
ourInstance = new Singleton1();
}
}
}
return ourInstance;
}
private Singleton1() {
}
}
饿汉(懒汉)模式
/**
* 线程安全的单例模式(饿汉)
*
* @author Chris
* @date 2020/02/28 23:45
* @since 1.0.0
*/
public class Singleton2 {
private static Singleton2 ourInstance = new Singleton2();
public static Singleton2 getInstance() {
return ourInstance;
}
private Singleton2() {
}
}
饱汉与饿汉模式的区别在于,加载的时机。
静态内部类模式
/**
* JVM层面保证了只会有一个实例对象。那么问题来了,这种方式和饿汉模式又有什么区别呢?
* 不也是立即加载么?实则不然,加载一个类时,其内部类不会同时被加载。
* 一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。
*
* @author Chris
* @date 2020/02/28 23:54
* @since 1.0.0
*/
public class Singleton3 {
private Singleton3() {
}
private static class SingletonStaticInner {
private static SingletonStaticInner singletonStaticInner = new SingletonStaticInner();
}
public static SingletonStaticInner getInstance() {
return SingletonStaticInner.singletonStaticInner;
}
/** 保证序列化与反序化时也能够是单例 */
protected Object readResolve() {
System.out.println("调用了readResolve方法");
return SingletonStaticInner.singletonStaticInner;
}
}
// 序列化与反序列化
// try {
// SingletonStaticInner serialize = SingletonStaticInner.getInstance();
// System.out.println(serialize.hashCode());
// //序列化
// FileOutputStream fo = new FileOutputStream("tem");
// ObjectOutputStream oo = new ObjectOutputStream(fo);
// oo.writeObject(serialize);
// oo.close();
// fo.close();
// //反序列化
// FileInputStream fi = new FileInputStream("tem");
// ObjectInputStream oi = new ObjectInputStream(fi);
// SingletonStaticInner serialize2 = (SingletonStaticInner) oi.readObject();
// oi.close();
// fi.close();
// System.out.println(serialize2.hashCode());
// } catch (Exception e) {
// e.printStackTrace();
// }