首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Java单例---双重校验详解

双重校验单例 什么是单例模式?...单例保证一个对象JVM中只能有一个实例 直接上代码吧: /** * 双重校验的单例 */ public class DoubleLock implements Serializable{...public static DoubleLock getInstance(){ //第一次判断,假设会有好多线程,如果doubleLock没有被实例化,那么就会到下一步获取,...是null,他就实例化了doubleLock,然后他出了, //这时候线程B经过等待A释放的,B获取了,如果没有第二个判断,那么他还是会去new DoubleLock...注释写的很清楚了,大家自己看哈 上面代码埋了一个坑,就是这个类实现类implements Serializable接口,这就会使这个类在序列化的时候单例被破坏,这个问题的解决方式和原理请看我的另一篇博客:java

22950
您找到你想要的搜索结果了吗?
是的
没有找到

Java单例模式中双重检查的问题

在努力创建更有效的代码时,Java 程序员们创建了双重检查锁定习语,将其和单例创建模式一起使用,从而限制同步代码量。...然而,由于一些不太常见的 Java 内存模型细节的原因,并不能保证这个双重检查锁定习语有效。 它偶尔会失败,而不是总失败。此外,它失败的原因并不明显,还包含 Java 内存模型的一些隐秘细节。...由于 instance 仍旧为 null,线程 2 试图获取 //1 处的。然而,由于线程 1 持有该,线程 2 在 //1 处阻塞。 线程 2 被线程 1 预占。...线程 2 获取 //1 处的并检查 instance 是否为 null。...由于线程 1 目前持有此,线程 2 被阻断。 线程 1 然后完成 //4 处的执行。

1.8K20

双重检查为什么要使用volatile字段?

双重的由来 单例模式中,有一个DCL(双重)的实现方式。在Java程序中,有时候可能需要推迟一些高开销的对象初始化操作,并且只有在使用这些对象时才开始初始化。...后来,提出了一个“聪明”的技巧:双重检查锁定(Double-Checked Locking)。想通过双重检查锁定来降低同步的开销。下面是使用双重检查锁定来实现延迟初始化的实例代码。.../** * 双重检查锁定 * * @author xiaoshu */ public class DoubleCheckedLocking { private static Instance...问题的根源 前面的双重检查锁定实例代码的第4处(instance = new Instance();)创建了一个对象。这一行代码可以分解为如下的3行伪代码。...在执行类的初始化期间,JVM会去获取一个.这个可以同步多个线程对同一个类的初始化。

1.3K10

服务端性能优化之双重检查

简介 早前的文章中讨论过服务端性能优化之异步查询转同步,在本文中,将讨论双重检查锁定设计模式。通过简单地事先检查锁定条件,该模式减少了锁定获取的次数,通常可以提高性能。...下面是之前关于和线程安全的文章的一些文章: Java服务端两个常见的并发错误 操作的原子性与线程安全 快看,i++真的不安全 原子操作组合与线程安全 单例的Demo 首先,让我们看一个具有严格同步的简单单例...要解决此问题,我们可以首先验证是否需要首先创建对象,只有在这种情况下,我们才能获取。...实际上,Java内存模型允许发布仅仅部分初始化的对象,而这又可能导致其他BUG。...替代方案 即使经过双重检查的锁定可能会加快速度,但它至少存在两个问题: 由于它要求volatile关键字才能正常工作,因此它与Java 1.4及更低版本不兼容 它很冗长,使代码难以阅读 由于这些原因,让我们研究没有这些缺陷的其他方案

82510

单例模式-双重检查(DCL)和volatile 的应用

单例模式-双重检查(DCL, 即 double-checked locking) 代码示例如下: package com.hsy.demo; /** * 懒汉单例 * * 优点:懒加载,线程安全...} } } return lazySingleton; } } 解释说明 优点:懒加载,线程安全,效率较⾼ 缺点:实现较复杂 这⾥的双重检查是指两次...⾮空判断,指的是 synchronized 加锁,为什么要进⾏双重判断,其实很简单,第⼀重判断,如果实例已经存在,那么就不再需要进⾏同步操作,⽽是直接返回这个实例,如果没有创建,才会进⼊同步块,同步块的...关于内部的第⼆重空判断的作⽤,当多个线程⼀起到达位置时,进⾏竞争,其中⼀个线程获取,如果是第⼀次进⼊则为 null,会进⾏单例对象的创建,完成后释放,其他线程获取后就会被空判断拦截,直接返回已创建的单例对象...简单说明⼀下,双重检查中使⽤ volatile 的两个重要特性:可⻅性、禁⽌指令重排序。 这⾥为什么要使⽤ volatile ?

66430

JUC并发编程之单例模式双重检验陷阱

1 前言 我在上一篇文章聊volatile的时候,埋下了一个问题,在并发情况下单例模式双重检验可能会存在的问题,那么本文就来详细分析分析它。...2 浅谈单例模式双重检验陷阱 首先看一段代码 public class Test04 { private static Test04 test04; public static Test04...} } //-----输出结果 com.dream.sunny.Test04@3f99bd52 com.dream.sunny.Test04@3f99bd52 true 如上是一段单例模式中的懒汉模式双重检验...双重检验问题解决方案 回头看下我们出问题的双重检查程序,它是满足as-if-serial语义的吗?是的,单线程下它没有任何问题,但是在多线程下,会因为重排序出现问题。...volatile是Java虚拟机提供的轻量级的同步机制。

44630

Java

java中的乐观基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。...java中的悲观就是Synchronized,AQS框架下的则是先尝试cas乐观去获取,获取不到,才会转换为悲观,如RetreenLock。...java中的 1.自旋 自旋原理非常简单,如果持有的线程能在很短时间内释放资源,那么那些等待竞争的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有的线程释放后即可立即获取...synchronized会导致争用不到的线程进入阻塞状态,所以说它是java语言中一个重量级的同步操纵,被称为重量级,为了缓解上述性能问题,JVM从1.5开始,引入了轻量与偏向,默认启用了自旋...偏向 Java偏向(Biased Locking)是Java6引入的一项多线程优化。

1.5K00

单例模式双重检查模式为什么必须加 volatile?

单例模式双重检查模式为什么必须加 volatile?...知道单例模式是一种很常见的设计模型,其目的就是为了避免创建过多的对象,给jvm造成比较大的压力,之前也对单例模型进行了比较详细的描述,详情参考我之前博客:链接 如果要实现一种线程安全的单例模型,一般都会采用双重检查模式...Singleton(); } } } return instance; } } 这里,就会有疑问,为什么要双重检查...答:这里分情况,如果不用第一个if判断,在多线程情况下,所有的线程都会进行抢,所以其实就是串行执行的;如果不用第二个if判断,因为经过第一个if判断,多个线程都会进来,不过只有一个线程能抢到,因为singleton...对象是null,所以会进行new Singleton,这种情况,如果不加第二个if判断,第一个线程创建对象之后,之后线程会继续创建的,所以这种就没做到单例 双重检查的原因知道之后,为什么要加volatile

1.1K30

JAVA

java 中的乐观基本都是通过 CAS 操作实现的,CAS 是一种更新的原子操作,比较当前值跟传入 值是否一样,一样则更新,否则失败。...java中的悲观就是Synchronized,AQS框架下的则是先尝试cas乐观去获取,获取不到, 才会转换为悲观,如 RetreenLock。...3.自旋 自旋原理非常简单,如果持有的线程能在很短时间内释放资源,那么那些等待竞争 的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋), 等持有的线程释放后即可立即获取...但是如果的竞争激烈,或者持有的线程需要长时间占用执行同步块,这时候就不适合 使用自旋了,因为自旋锁在获取前一直都是占用 cpu 做无用功,占着 XX 不 XX,同时有大量 线程在竞争一个,会导致获取的时间很长...所以这种情况下我们要关闭自旋;自旋时间阈值(1.6 引入了适应性自旋) 自旋的目的是为了占着 CPU 的资源不释放,等到获取到立即进行处理。但是如何去选择 自旋的执行时间呢?

66010

双重检查单例模式为什么要用volatile关键字?

前言 从Java内存模型出发,结合并发编程中的原子性、可见性、有序性三个角度分析volatile所起的作用,并从汇编角度大致说了volatile的原理,说明了该关键字的应用场景;在这补充一点,分析下...这个方法首先判断变量是否被初始化,没有被初始化,再去获取。获取之后,再次判断变量是否被初始化。第二次判断目的在于有可能其他线程获取过,已经初始化改变量。第二次检查还未通过,才会真正初始化变量。...这个方法检查判定两次,并使用,所以形象称为双重检查锁定模式。 这个方案缩小的范围,减少的开销,看起来很完美。然而这个方案有一些问题却很容易被忽略。...Java 语言规规定了线程执行程序时需要遵守 intra-thread semantics。**intra-thread semantics ** 保证重排序不会改变单线程内的程序执行结果。...上面错误双重检查锁定的示例代码中,如果线程 1 获取到进入创建对象实例,这个时候发生了指令重排序。

1.9K00

java的各类

可重入递归,同一个线程,外层函数获得,内层的也获得。...finally { lock.unlock(); } }}多线程的判断用while if只适合两个线程的判断synchronized和lock的区别参考文章存在层次上synchronized: Java...的关键字,在jvm层面上Lock: 是一个接口的释放synchronized: 1、以获取的线程执行完同步代码,释放 2、线程执行发生异常,jvm会让线程释放Lock: 在finally中必须释放...: 在发生异常时候会自动释放占有的,因此不会出现死锁Lock: 发生异常时候,不会主动释放占有的,必须手动unlock来释放,可能引起死锁的发生的状态synchronized: 无法判断Lock...当线程执行遇到monitorenter指令时会尝试获取内置,如果获取计数器+1,如果没有获取则阻塞;当遇到monitorexit指令时计数器-1,如果计数器为0则释放

17150

javacas(java的实现原理)

一、 Java 1.常见的有synchronized和Lock() ①synchronized 是jvm层面实现的,可以直接用,不过要锁住某个对象;lock是属于j.u.c包下的接口,用的时候要实现...@lock与synchronized相比,lock添加一些其他特性,如中断等候和定时等候。...2.悲观与乐观 ①悲观认为世界是悲观的,当去拿数据的时候就上锁,这样别人想拿这个就会阻塞直到拿到,传统的数据库用到了这种,像行,表等,读,写等,都是在做操作之前先上锁。...再比如Java里面的同步原语synchronized关键字的实现也是悲观。 ②乐观,认为一般并发是不会发生的,所以不会上锁。...基于CAS(无编程)实现,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制(解决ABA问题)。乐观适用于多读的应用类型,这样可以提高吞吐量。

53220

Java死锁、活,悲观、乐观

Java中导致饥饿的原因:  高优先级线程吞噬所有的低优先级线程的CPU时间。  线程被永久堵塞在一个等待进入同步块的状态,因为其他线程总是能在它之前持续地对该同步块进行访问。 ...传统的关系型数据库里边就用到了很多这种机制,比如行,表等,读,写等,都是在做操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观。...在Javajava.util.concurrent.atomic包下面的原子变量类就是使用了乐观的一种实现方式CAS实现的。...java中的Compare and Swap即CAS ,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,...从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。

43830

Java的乐观,悲观,读写,递归

我们都知道在 Java 中为了保证一些操作的安全性,就会涉及到使用,但是你对 Java了解的有多少呢?Java 都有哪些?以及他们是怎么实现的,今天了不起就来说说关于 Java。...在 Java 中,乐观通常是通过版本号、时间戳或其他状态信息来实现的。以下是乐观锁在 Java 中的一些常见实现方式: 版本号机制: 数据表中增加一个“版本号”字段。 读取数据时,同时读取版本号。...ReentrantLock类: Javajava.util.concurrent.locks.ReentrantLock类提供了重入的实现,这是一种悲观。...递归 Java中的递归(ReentrantLock)是java.util.concurrent.locks包下提供的一种可重入的互斥,它是悲观的一种实现。...读写 Java中的读写(ReadWriteLock)是一种允许多个读线程和单个写线程访问共享资源的同步机制。

10000
领券