饿汉式:私有化构造方法,不管需不需要用到Mgr01实例,先创建一个实例,仅提供一个共有的获取实例的方法(线程安全)
懒汉式:私有化构造方法,提供一个静态获取Mgr03实例的方法(首先判断实例是否已经创建,没有创建才会开始创建实例)(线程不安全)
私有化构造方法,将获取实例的方法用synchronize修饰同步方法,效率不高原因:synchronize修饰方法需要注意同步代码的范围不能太大也不能太小,太大效率不高,太小线程不安全(线程安全,效率不高)
还是线程不安全,原因:一开始还没有创建实例,多个线程一起去判断INSTANCE发现为NULL,接下来这些线程就会轮流争抢锁去创建实例(线程不安全)
双重判断:私有化构造器,首先多线程一起去判断INSTANCE是否为NULL,等于NULL,一起去抢锁,
轮流抢到锁去创建对象,因为再一次
是同步在进行一次判断(线程安全、效率高)
以上还有一个问题:要不要加volatile?为什么要加volatile
volatile的两个作用:1、线程可见性 2、禁止指令重排序
1、线程可见性的概念(volatile)
一个线程对数据的修改会后,另一个线程需要重新去内存读取
例如:int x ,y;没有加volatile修饰,线程不安全,加了之后一个线程对数据的修改会后,另一个线程需要重新去内存读取。
2、在介绍volatile的禁止指令重排序前,先介绍一下指令重排序的例子:
出现指令重排序例子:
从汇编层面分析创建对象的过程
问题分析:(这边还有一点小问题,总感觉有点不对劲,暂时没想起来哪里不对劲)
接下来我们分析volatile如何解决指令重排序的
现介绍两种常用的禁止指令重排序的方法
1、java层面:用volatile修饰变量i
2、字节码层面:ACC_VOLATILE
3、JVM层面:内存屏障
4、hotspot层面:这边没有用原语的方式保证有序性,本质采用锁总线的方式