为了账号安全,请及时绑定邮箱和手机立即绑定

【九月打卡】第12天++单例模式 二

标签:
设计模式

课程名称:Java设计模式精讲 Debug方式+内存分析

课程章节:第6章 单例模式

主讲老师:Geely

课程内容:

1)双重检验和防止重排序volatile实现单例模式?

  1. **对方案1进行改造,减少锁的判断。**可以先判断对象是否为null。这样如果对象已经存在,就不用去判断是否存在锁的问题。

  2. 解决方案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修饰、已在编译期把结果放入常量池的静态字段除外),

总结:

  1. 遇到new, getstatic , putstatic和invokestatic这4条指令时,如果类没有初始化时,则需要先触发其初始化。

生成这4条指令的最常见Java代码场景是:使用new关键字实例化对象、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外),以及调用一个类的静态方法。

问题4)类初始化的顺序?

先静态,再父类,再子类

问题5)在方案2中多线程中重排序出现什么问题?

重排序在多线程中存在的问题。线程1要比线程0先访问对象,但是对象还没有初始化,会出现问题。

解决办法:方法1、不允许重排序。通过volatile。

方法2、运行重排序,但是不允许线程1看到重排序,也就是说不需要还没有初始化对象,就用引用类型访问。

名词:重排序:引用类型指向对象的执行过程的顺序。

doubleCheckSingleton = new lazyDoubleCheckSingleton()****; 重排序。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消