类的加载顺序
- 先执行父类的静态代码块和静态变量初始化,静态代码块和静态变量的执行顺序跟代码中出现的顺序有关。
- 执行子类的静态代码块和静态变量初始化。
- 执行父类的实例变量初始化
- 执行父类的构造函数
- 执行子类的实例变量初始化
- 执行子类的构造函数
单例模式:饿汉式
/**
* 单例模式:饿汉式
* 类加载的时候就完成了实例化
* 优点:没有线程的安全的问题
* 缺点:类的实例没有使用的时候就会创建,占用内存
*/
public class SingleModel1 {
private SingleModel1() {}
private final static SingleModel1 INSTANCE = new SingleModel1();
public static SingleModel1 getInstance() {
return INSTANCE;
}
}
单例模式:懒汉式1
/**
* 单例模式:懒汉式加载
* 获取实例的时候才会创建对象
* 优点:解决了对象过早的实例化问题,避免内存浪费
* 缺点:每次获取实例化的时候因为synchronized产生性能问题
*/
public class SingleModel2 {
//volatile关键字:保证内存的可见性;避免了指令重排问题,造成实例化未结束的时候,其他线程调用getInstance方法造成的实例的INSTANCE是不完全的,从而造成空指针异常
private volatile static SingleModel2 INSTANCE = null;
private SingleModel2() {
}
public synchronized SingleModel2 getInstance() {
if (INSTANCE == null) {
INSTANCE = new SingleModel2();
}
return SingleModel2.INSTANCE;
}
}
单例模式:懒汉式2
/**
* 单例模式:懒汉式加载
* 双重检查懒汉式
*/
public class SingleModel3 {
private static volatile SingleModel3 INSTANCE = null;
private SingleModel3() {
}
public static SingleModel3 getInstance() {
if (SingleModel3.INSTANCE == null) {
synchronized (SingleModel3.class) { //锁的位置不同,减少性能的浪费
INSTANCE = new SingleModel3();
}
}
return INSTANCE;
}
}
静态内部类 (推荐)
/**
* 静态内部类模式
*/
public class SingleModel4 {
private static class InstanceHolder {
private final static SingleModel4 singleModel4 = new SingleModel4();
}
public SingleModel4 getInstance() {
return InstanceHolder.singleModel4;
}
}
枚举方式(推荐)
/**
* 枚举方式
*/
public class SingleModel5 {
private SingleModel5() {
}
public enum InstanceEnum {
INSTANCE;
private final SingleModel5 instance;
InstanceEnum() {
instance = new SingleModel5();
}
}
public SingleModel5 getInstance() {
return InstanceEnum.INSTANCE.instance;
}
}
举例:
单例的线程池
/** * @Auther: ZhangSuchao * @Date: 2020/6/9 17:36 */ public class SingleThreadPool { private static class ThreadPoolHolder { private static ThreadPoolExecutor pool = new ThreadPoolExecutor(20, 200, 60L, TimeUnit.SECONDS, new SynchronousQueue()); } public static ThreadPoolExecutor getInstance() { return ThreadPoolHolder.pool; } }
直接通过
SingleThreadPool.getInstance() 获取线程池实例
备注:也可以通过ioc容器管理,标记成单例模式(更简单),理论上ioc管理的单例,不是真正的单例,因为控制不了其他人员使用new的方式创建