单例模式
饿汉式 DCL懒汉式
1.饿汉式
package JUC;
/**
* 饿汉式 浪费内存
*/
public class SingletonHungry {
private byte[] data1 = new byte[1024*1024];
private byte[] data2 = new byte[1024*1024];
private byte[] data3 = new byte[1024*1024];
private byte[] data4 = new byte[1024*1024];
private SingletonHungry() {
System.out.println(Thread.currentThread().getName());
}
private final static SingletonHungry HUNGRY = new SingletonHungry();
public static SingletonHungry getInstance() {
return HUNGRY;
};
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
SingletonHungry.getInstance();
}).start();
}
}
}
2.懒汉式
package JUC;
/**
* 懒汉式单例 双重检测锁+volatile防止指令重排
*/
public class SingletonLazyMan {
private SingletonLazyMan(){
System.out.println(Thread.currentThread().getName());
}
private volatile static SingletonLazyMan lazyMan;
//双重检测锁 DCL懒汉式
public static SingletonLazyMan getInstance() {
if (lazyMan==null) {
synchronized (SingletonLazyMan.class) {
if (lazyMan==null) {
lazyMan = new SingletonLazyMan();
/**
* 不是原子性操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把对象指向这个空间
*
* 指令重排 123
* 但是如果执行132 A
* B
*/
}
}
}
return lazyMan; //此时SingletonLazyMan还没有完成构造
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
SingletonLazyMan.getInstance();
}).start();
}
}
}
2.1反射破坏单例
package JUC;
import java.lang.reflect.Constructor;
/**
* 懒汉式单例 双重检测锁+volatile防止指令重排
*/
public class SingletonLazyMan {
private SingletonLazyMan(){
System.out.println(Thread.currentThread().getName());
}
private volatile static SingletonLazyMan lazyMan;
//双重检测锁 DCL懒汉式
public static SingletonLazyMan getInstance() {
if (lazyMan==null) {
synchronized (SingletonLazyMan.class) {
if (lazyMan==null) {
lazyMan = new SingletonLazyMan();
/**
* 不是原子性操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把对象指向这个空间
*
* 指令重排 123
* 但是如果执行132 A
* B
*/
}
}
}
return lazyMan; //此时SingletonLazyMan还没有完成构造
}
public static void main(String[] args) throws Exception, SecurityException {
SingletonLazyMan lazyMan = SingletonLazyMan.getInstance();
Constructor<SingletonLazyMan> constructor = SingletonLazyMan.class.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonLazyMan lazyMan2 = constructor.newInstance();
if (lazyMan == lazyMan2) {
System.out.println("相等");
}else {
System.out.println("不相等");
}
}
}
2.2改良懒汉式单例 (三重检测)
package JUC;
import java.lang.reflect.Constructor;
/**
* 懒汉式单例 三重检测锁+volatile防止指令重排
*/
public class SingletonLazyMan {
private SingletonLazyMan(){
//三重检测
synchronized (SingletonLazyMan.class) {
if (lazyMan!=null) {
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
System.out.println(Thread.currentThread().getName());
}
private volatile static SingletonLazyMan lazyMan;
//双重检测锁 DCL懒汉式
public static SingletonLazyMan getInstance() {
if (lazyMan==null) {
synchronized (SingletonLazyMan.class) {
if (lazyMan==null) {
lazyMan = new SingletonLazyMan();
/**
* 不是原子性操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把对象指向这个空间
*
* 指令重排 123
* 但是如果执行132 A
* B
*/
}
}
}
return lazyMan; //此时SingletonLazyMan还没有完成构造
}
public static void main(String[] args) throws Exception, SecurityException {
//SingletonLazyMan lazyMan = SingletonLazyMan.getInstance();
Constructor<SingletonLazyMan> constructor = SingletonLazyMan.class.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonLazyMan lazyMan2 = constructor.newInstance();
SingletonLazyMan lazyMan3 = constructor.newInstance();
if (lazyMan == lazyMan2) {
System.out.println("相等");
}else {
System.out.println("不相等");
}
}
}
2.3改良单例信号灯法
package JUC;
import java.lang.reflect.Constructor;
/**
* 懒汉式单例 三重检测锁+volatile防止指令重排
*/
public class SingletonLazyMan {
//信号灯
private static boolean gouzi = false;
private SingletonLazyMan(){
//三重检测
synchronized (SingletonLazyMan.class) {
if (gouzi==false) {
gouzi = true;
} else {
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
System.out.println(Thread.currentThread().getName());
}
private volatile static SingletonLazyMan lazyMan;
//双重检测锁 DCL懒汉式
public static SingletonLazyMan getInstance() {
if (lazyMan==null) {
synchronized (SingletonLazyMan.class) {
if (lazyMan==null) {
lazyMan = new SingletonLazyMan();
/**
* 不是原子性操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把对象指向这个空间
*
* 指令重排 123
* 但是如果执行132 A
* B
*/
}
}
}
return lazyMan; //此时SingletonLazyMan还没有完成构造
}
public static void main(String[] args) throws Exception, SecurityException {
//SingletonLazyMan lazyMan = SingletonLazyMan.getInstance();
Constructor<SingletonLazyMan> constructor = SingletonLazyMan.class.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonLazyMan lazyMan2 = constructor.newInstance();
SingletonLazyMan lazyMan3 = constructor.newInstance();
if (lazyMan == lazyMan2) {
System.out.println("相等");
}else {
System.out.println("不相等");
}
}
}
2.4破坏单例信号灯
package JUC;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* 懒汉式单例 三重检测锁+volatile防止指令重排
*/
public class SingletonLazyMan {
//信号灯
private static boolean gouzi = false;
private SingletonLazyMan(){
//三重检测
synchronized (SingletonLazyMan.class) {
if (gouzi==false) {
gouzi = true;
} else {
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
System.out.println(Thread.currentThread().getName());
}
private volatile static SingletonLazyMan lazyMan;
//双重检测锁 DCL懒汉式
public static SingletonLazyMan getInstance() {
if (lazyMan==null) {
synchronized (SingletonLazyMan.class) {
if (lazyMan==null) {
lazyMan = new SingletonLazyMan();
/**
* 不是原子性操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把对象指向这个空间
*
* 指令重排 123
* 但是如果执行132 A
* B
*/
}
}
}
return lazyMan; //此时SingletonLazyMan还没有完成构造
}
public static void main(String[] args) throws Exception, SecurityException {
//获取属性 改为private允许访问
Field[] fields = SingletonLazyMan.class.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
field.setAccessible(true);
}
Field field = SingletonLazyMan.class.getDeclaredField("gouzi");
//SingletonLazyMan lazyMan = SingletonLazyMan.getInstance();
Constructor<SingletonLazyMan> constructor = SingletonLazyMan.class.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonLazyMan lazyMan2 = constructor.newInstance();
//修改属性
field.set(lazyMan2, false);
SingletonLazyMan lazyMan3 = constructor.newInstance();
if (lazyMan3 == lazyMan2) {
System.out.println("相等");
}else {
System.out.println("不相等");
}
}
}
3.使用枚举 保护单例模式(防止反射攻击)
3.1为什么枚举可以保护 单例模式?
3.2 枚举创建单例
package JUC;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 枚举懒汉式单例
*/
public enum EnumSingletonLazyMan {
INSTANCE;
public EnumSingletonLazyMan getInstance() {
return INSTANCE;
}
}
class TTTT{
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
EnumSingletonLazyMan e1 = EnumSingletonLazyMan.INSTANCE;
Constructor<EnumSingletonLazyMan> constructor = EnumSingletonLazyMan.class.getDeclaredConstructor();
constructor.setAccessible(true);
//in thread "main" java.lang.NoSuchMethodException: JUC.EnumSingletonLazyMan.<init>()
EnumSingletonLazyMan e2 = constructor.newInstance();
if (e1 == e2) {
System.out.println("相等");
}else {
System.out.println("不相等");
}
}
}
而得到的是这个
并非
3.3查看底层 反编译
找到.class目录下
进行反编译
也是有空参的,
3.4 使用jad.exe
看到最终源码 这里是有参构造器。
再次修改代码
4.总结
单例不安全,无论怎么修改都能被反射破解。
枚举创建单例安全,可以通过 专业编译器反编译出来,(枚举类)真实的源码。