4、单例模式
2019-12-16 本文已影响0人
lois想当大佬
一、单例模式-饿汉模式
1、定义一个不可变的静态变量并直接实例化
2、构造函数私有化
3、定义一个静态函数总是返回实例
package com.hello.single;
/**
* 单例模式-饿汉模式
* 1、定义一个不可变的静态变量并直接实例化
* 2、构造函数私有化
* 3、定义一个静态函数总是返回实例
*
* 问题:
* 1、EhanSingle类在加载字节码到虚拟机的时候就会实例化这个实例,
* 在你没有使用该单例的时候,该单例却被加载了,如果该单例很大的话,将会浪费很多的内存
*/
public class EhanSingle {
private static final EhanSingle single = new EhanSingle();
private EhanSingle(){}
public static EhanSingle getInstance() {
return single;
}
}
存在问题:
1、EhanSingle类在加载字节码到虚拟机的时候就会实例化这个实例,在你没有使用该单例的时候,该单例却被加载了,如果该单例很大的话,将会浪费很多的内存。
二、单例模式-懒汉模式
1、定义一个静态变量实例
2、定义一个静态函数创建并返回实例
3、私有化构造函数
package com.hello.single;
/**
* 单例模式-懒汉模式
* 1、定义一个静态变量实例
* 2、定义一个静态函数创建并返回实例
* 3、私有化构造函数
* 问题
* 1、多线程环境下不能保证单例
*/
public class LanhanSingle1 {
private static LanhanSingle1 single;
private LanhanSingle1(){};
public static LanhanSingle1 getInstance() {
// 如果对象不是null,就直接返回实例,从而保证单例。也可以保证不浪费内存(不调用则不产生对象)
if (single == null) {
single = new LanhanSingle1();
}
return single;
}
}
存在问题:
1、多线程环境下不能保证单例
三、单例模式-懒汉模式-加锁
1、定义一个静态变量实例
2、定义一个静态函数创建并返回实例
3、私有化构造函数
4、同步锁确保在多线程环境下保证单例
package com.hello.single;
/**
* 单例模式-懒汉模式
* 1、定义一个静态变量实例
* 2、定义一个静态函数创建并返回实例
* 3、私有化构造函数
* 4、同步锁确保在多线程环境下保证单例
* 问题
* 1、正确的对象实例化流程:
* a、在堆空间分配内存
* b、执行构造方法进行初始化
* c、将对象指向内存中分配的内存空间,也就是地址
* 2、但是,由于编译器会对代码进行重排序优化,如果执行的顺序是acb,则也会产生错误对象。
*/
public class SynLanhanSingle2 {
private static SynLanhanSingle2 single;
private SynLanhanSingle2(){};
public static SynLanhanSingle2 getInstance() {
// 多线程访问,不做控制、不影响性能
if (single == null) {
// 此时,如果多个线程进入,则进入同步块
synchronized (SynLanhanSingle2.class) {
// 此时,第一个进入的线程判断为null,但是第二个线程进来时已经不是null了
if (single == null) {
single = new SynLanhanSingle2();
}
}
}
// 如果不为null,不会影响性能,只有第一次才会影响性能
return single;
}
}
四、 单例模式-懒汉模式-静态内部类
1、静态内部类实例化对象
2、定义一个静态函数返回实例
3、私有化构造函数
package com.hello.single;
/**
* 单例模式-懒汉模式
* 1、静态内部类实例化对象
* 2、定义一个静态函数返回实例
* 3、私有化构造函数
* 问题:
* 1、反射破坏
* 2、反序列化破坏
*/
public class InnerLanhanSingle3 {
private InnerLanhanSingle3(){};
public static InnerLanhanSingle3 getInstance() {
return InnerClass.single;
}
/**
* 静态内部类的虚拟机机制,只有当访问类的时候,才会加载,
* 因此, 既保证了懒加载(节省内存),又保证了单例与线程安全。
*/
private static class InnerClass{
private static final InnerLanhanSingle3 single = new InnerLanhanSingle3();
}
}
上一篇:模板方法模式