单例模式(流程)

1、饿汉式

public class Hungary {

    private final static Hungary HUNGARY = new Hungary();

    public static Hungary getInstance() {
        return HUNGARY;
    }

    public static void main( String[] args ) {
        Hungary instance1 = Hungary.getInstance();
        Hungary instance2 = Hungary.getInstance();
        System.out.println(instance1);
        System.out.println(instance2);
    }
}
  • 优点:
    1. 在类加载的同时已经创建好一个静态对象,调用时反应速度快;典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。
    2. 不存在线程安全问题;因为虚拟机保证只会装载一次,在装载类的时候是不会发生并发的
  • 缺点:
    1. 资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化

2、懒汉式

public class LazyMan {

    private static LazyMan lazyMan;

    public static LazyMan getInstance() {
        if (lazyMan == null) {
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }
}
  • 优点
    1. 资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法
  • 缺点
    1. 多线程下并发不安全

2.1、懒汉式改进(解决并发问题)

public class LazyMan {

    private static LazyMan lazyMan;

    public synchronized  static LazyMan getInstance() {
        if (lazyMan == null) {
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }
}
  • 缺点: 第一次加载时不够快,多线程使用不必要的同步开销大

2.2、懒汉式改进(双重检测)

public class LazyMan {

    private static LazyMan lazyMan;

    public  static LazyMan getInstance() {
        if (lazyMan == null) {
            synchronized (LazyMan.class){
                if(lazyMan == null){
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }
}
  • 缺点: 第一次加载时反应不快,由于指令重排,会造成失败
  1. 在堆中开辟对象所需空间,分配地址
  2. 根据类加载的初始化顺序进行初始化
  3. 将内存地址返回给栈中的引用变量

2.3、懒汉式改进(双重检测改进volatile)

public class LazyMan {

    private static volatile LazyMan lazyMan;

    public  static LazyMan getInstance() {
        if (lazyMan == null) {
            synchronized (LazyMan.class){
                if(lazyMan == null){
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }
}

2.4、懒汉式改进(防止部分反射破坏)

public class LazyMan {

    private static LazyMan lazyMan;

    private LazyMan() {
        synchronized (LazyMan.class) {
            if (lazyMan!=null){
                throw new RuntimeException("不要试图使用反射破坏异常");
            }
        }
    }

    //双重检测锁模式 懒汉式单例
    public static LazyMan getInstance() {
        if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }
    
    public static void main( String[] args ) throws Exception {

     Constructor<LazyMan1> declaredConstructor = LazyMan1.class.getDeclaredConstructor(null);
     declaredConstructor.setAccessible(true);
     
     LazyMan1 instance = LazyMan1.getInstance();

     //可以保证单例
     LazyMan1 instance2 = declaredConstructor.newInstance();

     System.out.println(instance);
     System.out.println(instance2);

 }
}
  • 缺点:只有先创建对象,再使用反射破坏时才起作用;如果使用反射创建对象,无效。

2.5、懒汉式改进(防止部分反射破坏,2.4改进)

public class LazyMan {
private static boolean isCreate = false;

    private LazyMan() {
        synchronized (LazyMan.class) {
            if (isCreate == false) {
                isCreate = true;
            } else {
                throw new RuntimeException("不要试图使用反射破坏异常");
            }
        }
    }

    private static LazyMan lazyMan;

    //双重检测锁模式 懒汉式单例
    public static LazyMan getInstance() {
        if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan();    //不是一个原子性操作
                }
            }
        }
        return lazyMan;
   }
}
  • 如果直接使用反射破坏标志位依旧无法实现单例
public static void main(String[] args) throws Exception{
        Field flag = LazyMan.class.getDeclaredField("isCreate");
        flag.setAccessible(true);
        Constructor<LazyMan> declaredConstructor = LazyMan2.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan instance1 = declaredConstructor.newInstance();
        System.out.println(instance1);
        flag.set(instance1,false);
        LazyMan instance2 = declaredConstructor.newInstance();
        System.out.println(instance2);
}

2.6、使用枚举防止被破坏

public enum EnumSingleton {

	INSTANCE;

	public EnumSingleton getInstance(){
		return INSTANCE;
	}
}

class Test{
 public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Constructor<EnumSingle> declaredConstructor =
                EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        EnumSingle instance = declaredConstructor.newInstance();
        EnumSingle instance2 = declaredConstructor.newInstance();
        System.out.println(instance);
        System.out.println(instance2);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值