1、单例模式
- 饿汉式
package com.liuxiang.Singleton;
//一上来就创建对象
public class TestSingleton {
//饿汉式 构造器私有 避免别人创建对象
private TestSingleton(){
}
// 饿汉式可能会造成浪费空间
private final static TestSingleton singleton = new TestSingleton();
public static TestSingleton getInstance(){
return singleton;
}
}
- 懒汉式
package com.liuxiang.Singleton;
public class TestSingleton {
//构造器私有 避免别人创建对象
private TestSingleton(){
}
// 懒汉式可能会造成浪费空间 volatile确保不会被指令重排
private volatile static TestSingleton singleton;
public static TestSingleton getInstance(){
if (singleton == null){
//多线程获取 需要使用synchronized 双重检测锁模式
synchronized (TestSingleton.class){
if (singleton == null){
singleton = new TestSingleton();
//DCL懒汉式双重检测机制,在极端情况下还是会出现问题
//new一个对象在正常情况下的执行流程应该是:
//1.分配内存空间
//2.执行构造方法,初始化对象
//3.把这个对象指向这个空间
//如果出现了指令重排123 变成了132 就会出现问题
//所以我们应该加上volatile确保不会发生指令重排
}
}
}
return singleton;
}
}
- 使用枚举确保单例模式不被反射破坏
package com.liuxiang.Singleton;
import java.lang.reflect.Constructor;
public class TestSingleton {
//构造器私有 避免别人创建对象
private TestSingleton(){
}
// 懒汉式可能会造成浪费空间 volatile确保不会被指令重排
private volatile static TestSingleton singleton;
public static TestSingleton getInstance(){
if (singleton == null){
//多线程获取 需要使用synchronized 双重检测锁模式
synchronized (TestSingleton.class){
if (singleton == null){
singleton = new TestSingleton();
}
}
}
return singleton;
}
//使用反射创建对象 破坏单例模式
public static void main(String[] args) throws Exception {
Constructor<TestSingleton> declaredConstructor = TestSingleton.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);//关闭安全检测
TestSingleton singleton1 = declaredConstructor.newInstance();//通过反射创建对象
TestSingleton singleton2 = declaredConstructor.newInstance();//通过反射创建对象
System.out.println(singleton1);
System.out.println(singleton2);
}
}
com.liuxiang.Singleton.TestSingleton@1b6d3586
com.liuxiang.Singleton.TestSingleton@4554617c
使用反射就可以绕过私有变量创建新的对象,我们查看反射的源码可以发现:反射机制不能操作枚举类