课程名称:Java设计模式精讲 Debug方式+内存分析
课程章节:第6章 单例模式
主讲老师:Geely
课程内容:
1)双重检验和防止重排序volatile实现单例模式?
-
**对方案1进行改造,减少锁的判断。**可以先判断对象是否为null。这样如果对象已经存在,就不用去判断是否存在锁的问题。
-
解决方案2中重排序问题。通过volatile,防止重排序。
if双重检测:
-
第一重是为了减少锁的判断。(因为直接在方法上加锁,每个线程都会先判断是否加锁。)
-
第二重是为了防止第一重判断已经进入等待synchronize代码块的线程。因为如果不加if判断是否为null,第二个进入synchronize的线程,
-
会再创建一个对象。(第二重检验是为了防止创建多个对象。)
单例2)静态内部类实现单例模式(线程安全,避免重排序问题)?
**实现的原理:类初始化锁只能被一个线程获取,**用来同步多个线程对一个类初始化。
类初始化会加载静态方法,静态代码块。
(初始化锁只被一个线程获取,所以是线程安全的,同时也是避免了重排序。因为它是锁住了整个初始化过程,所以不存在重排序问题。)
**/****
*** 静态内部类实现单例。**
*** 原理:类加载的延迟,类初始化锁只能被一个线程获取。**
*** 触发类初始化的几种情况。**
*** 类初始化的内容。**
*****
*** 注意:无论是那种实现单例的方式。私有的构造器一定要写,否则外部是可以实例化的。**
*/
public class StaticInnerClassSingleton {
private static class InnerClass{
private static StaticInnerClassSingleton staticInnerClassSingleton
= new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance(){
return InnerClass.staticInnerClassSingleton;
}
private StaticInnerClassSingleton(){}
}
public class th implements Runnable {
@Override
public void run() {
// lazySingleton singleton = lazySingleton.getInstance();
// lazyDoubleCheckSingleton singleton= lazyDoubleCheckSingleton.getDoubleCheckSingleton();
StaticInnerClassSingleton singleton = StaticInnerClassSingleton.getInstance();
System.out.println(Thread.currentThread().getName()+singleton);
}
}
public class test {
public static void main(String[] args) {
/* lazySingleton singleton = lazySingleton.getInstance();
System.out.println(singleton);*/
Thread th01 = new Thread(new th());
Thread th02 = new Thread(new th());
th01.start();
th02.start();
System.out.println(“end”);
}
}
基于 类初始化的延迟加载解决方案。
问题3)什么情况下会触发类初始化?
5种情况,下面只说最常用的一种情况。
第一种情况下有四个常用情况。
1、类被实例化。通过new关键字。
2、类的静态方法被调用。(invoke static function)
3、类中的静态成员变量被赋值。(putstatic)
4、类中的静态成员变量被使用,并且不是常量成员 (getstatic) (被final修饰、已在编译期把结果放入常量池的静态字段除外),
总结:
- 遇到new, getstatic , putstatic和invokestatic这4条指令时,如果类没有初始化时,则需要先触发其初始化。
生成这4条指令的最常见Java代码场景是:使用new关键字实例化对象、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外),以及调用一个类的静态方法。
问题4)类初始化的顺序?
先静态,再父类,再子类
问题5)在方案2中多线程中重排序出现什么问题?
重排序在多线程中存在的问题。线程1要比线程0先访问对象,但是对象还没有初始化,会出现问题。
解决办法:方法1、不允许重排序。通过volatile。
方法2、运行重排序,但是不允许线程1看到重排序,也就是说不需要还没有初始化对象,就用引用类型访问。
名词:重排序:引用类型指向对象的执行过程的顺序。
doubleCheckSingleton = new lazyDoubleCheckSingleton()****; 重排序。
共同学习,写下你的评论
评论加载中...
作者其他优质文章