1 原理解析
1.1 如何实现让后边线程看不到前边线程是否有序列化呢(综合上节看)
1.2 原理
1.3 5种初始化方法
1.4 单例类必须要有私有构造方法
2 代码演练
2.1 代码演练1
1 原理解析
1.1 如何实现让后边线程看不到前边线程是否有重排序呢(综合上节看)
参考2.1,使用基于类初始化的方案,使用静态内部类的单例模式来解决。
1.2 原理
jvm 在类的初始化阶段,也就是class被加载后并且被线程使用之前,都是类的初始化阶段。在这个阶段,会执行类的初始化。在此期间,jvm会获取锁,这个锁会同步多个线程对一个类的初始化。
基于上述特性,我们可以实现基于静态内部类并且线程安全的延迟初始化方案。基于类初始化的延迟加载解决方案。(即非构造线程无法看到重排序)(主要是因为类初始化是会上锁的,所以即使多线程去调用,只会有一个线程拿到锁去初始化,)
如下图:线程1看不到线程0是否发生了重排序
1.3 5种情况下,一个类(泛指,包括interface)会被立即初始化
a a类型实例被创建(new方法)
b a类声明的静态方法被调用
c a类声明的静态成员被赋值
d a类声明的静态成员被使用,并且该成员不是常量成员
e a类如果是顶级类,并且在类中有嵌套的断言语句
1.4 单例类必须要有私有构造方法
同上,必须要有,没有的话可以被外部类实例化
2 代码演练
2.1 代码演练1
线程类:
package com.geely.design.pattern.creational.singleton;
/**
* 注:该类为线程类,调用LazySingleton
*/
public class T implements Runnable{
/*@Override
public void run() {
LazySingleton lazySingleton = LazySingleton.getInstance();
System.out.println(Thread.currentThread().getName()+"==="+lazySingleton);
}*/
/*@Override
public void run() {
LazyDoubleCheckSingleton lazyDoubleCheckSingleton = LazyDoubleCheckSingleton.getInstance();
System.out.println(Thread.currentThread().getName()+"==="+lazyDoubleCheckSingleton);
}*/
@Override
public void run() {
StaticInnerClassSingleton staticInnerClassSingleton = StaticInnerClassSingleton.getInstance();
System.out.println(Thread.currentThread().getName()+"==="+staticInnerClassSingleton);
}
}
静态内部类:
package com.geely.design.pattern.creational.singleton;
public class StaticInnerClassSingleton {
/**
* 静态内部类
* 自己容易犯的错误:静态内部类不要加(),不是方法。
*/
private static class InnerClass{
private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance(){
//这里如何进行初始化呢?
return InnerClass.staticInnerClassSingleton;
}
/**
* 注意一定要写私有的构造函数,否则的话容易被外部类实例化该类
*/
private StaticInnerClassSingleton(){
}
}
诸葛