饿汉式单例
public class HungrySingleton {
private static final HungrySingleton INSTANCE = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return INSTANCE;
}
public static void main(String[] args) {
HungrySingleton mg1 = HungrySingleton.getInstance();
HungrySingleton mg2 = HungrySingleton.getInstance();
System.out.println(mg1 == mg2);
}
}
类加载到内存中,只有一个实例对象,JVM保证线程安全,建议使用
无论是否有使用到,都会创建并加载实例
懒汉式单例
public class LazySingleton {
private static LazySingleton INSTANCE;
private LazySingleton() {
}
public static LazySingleton getInstance() {
//先判断是否等于null 如果等于null,再创建
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new LazySingleton();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() ->{
System.out.println(LazySingleton.getInstance().hashCode());
}).start();
}
}
}
只有用到的时候才会创建实例
但是多线程情况下,存在无法保证只创建一个实例的问题
双重检查单例
public class DoubleCheck {
/**
* volatile
* 1:保证线程可见性 (MESI缓存一致性协议)
* 2:禁止指令重排序
*/
private static volatile DoubleCheck INSTANCE;
private DoubleCheck() {}
public static DoubleCheck getInstance() {
if (INSTANCE == null) {
synchronized (DoubleCheck.class) {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new DoubleCheck();
}
}
}
return INSTANCE;
}
}
懒汉式的前提下,避免了多线程情况下出现创建多实例的问题
静态内部类单例
public class StaticInnerClass {
private StaticInnerClass() {}
private static class StaticInnerClassHolder {
private final static StaticInnerClass INSTANCE = new StaticInnerClass();
}
public static StaticInnerClass getInstance() {
return StaticInnerClassHolder.INSTANCE;
}
}
JVM保证线程安全,加载外部类的时候,并不会加载内部类,实现懒汉式
枚举单例
public enum EnumSingleton {
INSTANCE;
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() ->{
System.out.println(EnumSingleton.INSTANCE.hashCode());
}).start();
}
}
}
解决多线程访问问题,并且防止反序列化
未完待续