参考链接:
1. 单例模式
参考链接:
1.1 饿汉式单例
package com.study.singleton;
/**
* @ClassName HungryMan
* @Description 饿汉式单例模式【不安全】
* @Author Jiangnan Cui
* @Date 2023/3/20 22:24
* @Version 1.0
*/
public class HungryMan {
/**
* 缺点:类加载期间就创建对象,容易造成资源浪费。即:当该类中放置了很多资源时,最开始加载可能会浪费空间,因为加载了也不使用。
*/
private byte[] data1 = new byte[1024*1204];
private byte[] data2 = new byte[1024*1204];
private byte[] data3 = new byte[1024*1204];
private byte[] data4 = new byte[1024*1204];
private byte[] data5 = new byte[1024*1204];
/**
* 私有构造方法限制产生多个对象
*/
private HungryMan() {
}
/**
* 最开始就创建对象,保证只有一个对象
*/
private static final HungryMan HUNGRY_MAN = new HungryMan();
/**
* 通过该方法获得实例对象
* @return
*/
public static HungryMan getInstance(){
return HUNGRY_MAN;
}
}
1.2 懒汉式单例
package com.study.singleton;
/**
* @ClassName LazyMan
* @Description 懒汉式单例模式:用的时候再创建【不安全】
* 单线程下安全,多线程下存在并发安全问题
* @Author Jiangnan Cui
* @Date 2023/3/20 22:33
* @Version 1.0
*/
public class LazyMan {
/**
* 私有构造方法限制产生多个对象
*/
private LazyMan(){
// 此处为了测试多线程并发安全问题
System.out.println(Thread.currentThread().getName() + " is ok");
}
private static LazyMan lazyMan = null;
/**
* 通过该方法获得实例对象
* @return
*/
public static LazyMan getInstance(){
if (lazyMan == null) {
lazyMan = new LazyMan();
}
return lazyMan;
}
public static void main(String[] args) {
// 多线程并发时存在线程安全问题
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
/**
* 输出的一个结果举例:
* Thread-0 is ok
* Thread-3 is ok
* Thread-2 is ok
* Thread-1 is ok
*/
}
}
1.3 懒汉式单例-DCL
package com.study.singleton;
import com.sun.org.apache.bcel.internal.generic.I2B;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* @ClassName LazyMan2
* @Description 懒汉式单例模式+双重锁校验优化+防止指令重排:DCL懒汉式【不安全】】
* 解决多线程下存在并发安全问题
* @Author Jiangnan Cui
* @Date 2023/3/20 22:33
* @Version 1.0
*/
public class LazyMan2 {
private static boolean secret = false;// 红绿灯
/**
* 私有构造方法限制产生多个对象
*/
private LazyMan2(){
// 解决反射破坏单例问题
synchronized (LazyMan2.class) {
if (secret == false) {
secret = true;
} else {
throw new RuntimeException("不要试图使用反射破坏异常!");
}
}
// 此处为了测试多线程并发安全问题
System.out.println(Thread.currentThread().getName() + " is ok");
}
/**
* 加volatile防止指令重排
*/
private volatile static LazyMan2 lazyMan2 = null;
/**
* 通过该方法获得实例对象
* @return
*/
public static LazyMan2 getInstance(){
if (lazyMan2 == null) {
synchronized (LazyMan2.class) {
if (lazyMan2 == null) {
/**
* new对象的过程中,不是一个原子性操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把这个对象指向这个空间
*
* CPU指令重排:1、3、2,此时lazyMan2还没有完成构造,需要加volatile保证指令不重排
*/
lazyMan2 = new LazyMan2();
}
}
}
return lazyMan2;
}
public static void main(String[] args) throws Exception {
/**
* 反射可以破坏单例
*/
// LazyMan2 instance1 = LazyMan2.getInstance();
// 2.再次调用反射:获取字段,无视私有
Field secret = LazyMan2.class.getDeclaredField("secret");
secret.setAccessible(true);//无视私有构造器
// 1.利用反射
Constructor<LazyMan2> declaredConstructor = LazyMan2.class.getDeclaredConstructor(null);
// 无视私有构造器
declaredConstructor.setAccessible(true);
// 创建新对象
LazyMan2 instance1 = declaredConstructor.newInstance();
// 3.重新设置
secret.set(instance1, false);
// 再次利用反射创建对象
LazyMan2 instance2 = declaredConstructor.newInstance();
System.out.println("instance1 = " + instance1);
System.out.println("instance2 = " + instance2);
}
}
1.4 静态内部类
package com.study.singleton;
/**
* @ClassName StaticInnerClass
* @Description 静态内部类单例模式【不安全】
* @Author Jiangnan Cui
* @Date 2023/3/20 23:31
* @Version 1.0
*/
public class StaticInnerClass {
private StaticInnerClass(){
}
public static StaticInnerClass getInstance(){
return InnerClass.STATIC_INNER_CLASS;
}
public static class InnerClass {
private static final StaticInnerClass STATIC_INNER_CLASS = new StaticInnerClass();
}
}
1.5 枚举
package com.study.singleton;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @ClassName SingleEnum
* @Description enum本身也是一个class类,jdk 1.5就有了
* @Author Jiangnan Cui
* @Date 2023/3/20 23:18
* @Version 1.0
*/
public enum SingleEnum {
INSTANCE;
public SingleEnum getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
SingleEnum instance1 = SingleEnum.INSTANCE;
Constructor<SingleEnum> declaredConstructor = SingleEnum.class.getDeclaredConstructor(String.class, int.class);//注意此处并不是无参构造方法,实际有String、int两个参数,要通过反编译工具jad.exe才能验证
declaredConstructor.setAccessible(true);
// SingleEnum instance2 = SingleEnum.INSTANCE;
SingleEnum instance2 = declaredConstructor.newInstance();
System.out.println("instance1 = " + instance1);
System.out.println("instance2 = " + instance2);
}
}
// Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
at com.study.singleton.Test.main(SingleEnum.java:26)
javap -p 类名.class反编译:
jad.exe反编译结果:

待完善
6万+

被折叠的 条评论
为什么被折叠?



