单例模式-懒汉式(双重检验)

上章节我们在懒汉式的单例模式上解决了多线程安全的问题,但解决问题的同时,新的问题也随之而来。

上节问题:

1、在静态方法(static)上添加关键字(synchronized同步锁),就是相当于在类上加锁,锁的范围大,损耗性能。

2、加锁、解锁过程消耗资源。

那么,我们该如何解决呢?

 1 public class lazyDoubleCheckSingleton {
 2
 3   private static lazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
 4
 5   private lazyDoubleCheckSingleton() {
 6
 7   }
 8   public static lazyDoubleCheckSingleton getInstance() {
 9     if (lazyDoubleCheckSingleton == null) {
10       synchronized (lazyDoubleCheckSingleton.class){
11         if (lazyDoubleCheckSingleton == null){
12           lazyDoubleCheckSingleton = new lazyDoubleCheckSingleton();             //1、分配内存给这个对象             //2、初始化对象             //3、设置lazyDoubleCheckSingleton,指向刚分配的内存地址
13  } 14  } 15  } 16 return lazyDoubleCheckSingleton; 17  } 18 }

此种方法就是懒汉模式的双重检测式,把锁加在方法里面,只有空的话才会加锁,不为空的话,直接return lazyDoubleCheckSingleton,大大节省了开销,但是这段代码,还存在着两大隐患,分别是9行、12行,首先在9行判断了是否为空,有可能是不为空的,他虽然不为空,但是是在12行还没完成初始化的情况下,12行的代码虽然是一行,确实经历了三个步骤,注释上2和3的顺序可能调换,进行重排序,也就是先指向内存地址,但是还没初始化对象。下面给大家开一个图。

这是单线程,介入多线程呢?

看吧,就出问题了呢,想要解决这个问题,有两种解决方案

1、不允许2、3进行重排序,加入了volatile关键字.
2、允许一个线程进行重排序,但不允许另外线程看到他的重排序。那么我们看看用第一种方案是怎么解决的呢?
/**
 * Created by sww_6 on 2019/4/10.
 * 双重检查
 * 1、不允许2、3进行重排序,加入了volatile关键字.
 * 2、允许一个线程进行重排序,但不允许另外线程看到他的重排序。
 * 划重点:
 * 1、在多线程的时候,cpu有共享内存。
 * 2、加入了volatile关键字之后,所有线程都能看到共享内存的最新状态,保证内存可见性。
 * <p>
 * 怎么保持内存一致性?
 * 用volatile修饰的共享变量,在进行写操作的时候,会多出来很多汇编代码,起到两个作用。
 * 1、是将当前处理器缓存行的数据写回到系统内存,写回内存的操作,会使在其他cpu里缓存了该内存的数据无效,其他cpu缓存的数据无效了,就会从共享内存同步数据。保证了内存的可见性。
 * 主要使用的是缓存一致性协议
 * <p>
 * 优点:
 * 既兼顾了性能,又兼顾了线程安全。
 */
public class lazyDoubleCheckSingleton {

    private volatile static lazyDoubleCheckSingleton lazyDoubleCheckSingleton = null; private lazyDoubleCheckSingleton() { } public synchronized static lazyDoubleCheckSingleton getInstance() { if (lazyDoubleCheckSingleton == null) { synchronized (lazyDoubleCheckSingleton.class) { if (lazyDoubleCheckSingleton == null) { lazyDoubleCheckSingleton = new lazyDoubleCheckSingleton(); } } } return lazyDoubleCheckSingleton; } }

好了,我们下期见!

 

原文地址:https://www.cnblogs.com/shenwen/p/10686682.html

时间: 2024-10-14 16:34:01

单例模式-懒汉式(双重检验)的相关文章

关于双重检验锁方法和内部类方法实现单例模式的实验

网上很多人说,使用双重检验锁方法实现单例模式可能会new多个实例,而内部类方法和枚举类方法完美解决了这个问题 因为Android很少使用枚举,本次只研究双重检验锁方法和内部类方法 双重检验锁方法: 代码如下: public class SingletonB { private static volatile SingletonB mInstance; private SingletonB() { System.out.println("双重检验锁方法单例模式"); } public s

单例模式,双重校验的懒汉式

/** * 单例模式,双重校验的懒汉式 */ public class bTestSingleton { public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); System.out.println(s1==s2); } } class Singleton{ private Singleton(){ } priv

单例模式和双重检测的小结

设计模式的经典模式之一--单例模式 这个也是面试经常被问起的面试,一般都要求手写 [饿汉模式]非延时加载 --以空间换时间 [懒汉模式]延时加载--以时间换空间 看似简单,但是在懒汉模式还隐藏了一个双重检测,其中还是涉及到JVM内存的"无序写入"问题(后面使用的 volatile ) 1.饿汉模式 比较简单,非延时加载,一上来就把对象给new出来了 <span style="font-family:Microsoft YaHei;font-size:14px;"

单例模式之双重检测锁

先来看看双重检测锁的实现以及一些简要的说明(本文主要说明双重检测锁带来的线程安全问题): /** * 单例模式之双检锁 * @author ring2 * 懒汉式升级版 */ public class Singleton3 { private static volatile Singleton3 instance; private Singleton3() {} public static Singleton3 getInstance() { //首先判断是否为空 if(instance==nu

单例模式 (懒汉式)ARC

为什么要使用单例模式:相比于代理更方便在不同类之间实现数据的传递,要点:保证某个类只有一个实例对象 1 static id _instance = nil;//定义一个静态全局变量 2 + (instancetype)allocWithZone:(struct _NSZone *)zone{ 3 4 if (!_instance ) {//如果存在直接返回,避免加锁过程 5 6 @synchronized(self) {//防止多线程抢夺资源, 7 8 if (_instance == nil)

线程安全的单例模式及双重检查锁—个人理解

在web应用中服务器面临的是大量的访问请求,免不了多线程程序,但是有时候,我们希望在多线程应用中的某一个类只能新建一个对象的时候,就会遇到问题. 首先考虑单线程,如果要求只能新建一个对象,那么构造函数我们要设为private.简单的想法: class singleton{ private singleton(){ //..... } private static singleton instance; public static singleton getinstance(){ if(insta

单例模式の懒汉式和饿汉式

单例模式,是用来解决一次只能实例化一个对象的问题. 根据对象实例化的先后,有两种实现方式: 懒汉式 饿汉式 下面是在代码中有详细的说明两种实现方法 package 设计模式; /* * 单例的设计模式(饿汉式) * 1.解决的问题:使得一个类只能够创建一个对象 * 2.如何实现 * */ public class SingletonTest { public static void main(String[] args) { Singleton s1 = Singleton.getInstanc

单例模式的双重检测

单例模式是设计模式中比较常见简单的一种,典型双重检测写法如下: public class SingletonClass { private volatile static SingletonClass instance = null; public static SingletonClass getInstance() { if (instance == null) { synchronized (SingletonClass.class) { if(instance == null) { in

java基础——线程安全的单例模式懒汉式

package savesingleton; /* 使用同步将单例模式中的懒汉式改写成线程安全的 @author zsben @create 2020-01-03 22:22 */ class Bank{ private Bank(){} private static Bank instance = null; /*public static synchronized Bank getInstance(){ if(instance == null){ instance = new Bank();