关于Java锁机制面试官会怎么问

  • 时间:
  • 浏览:0
  • 来源:5分排列3_5分排列3官网

CAS与Synchronized的使用情景

2、对于资源竞争严重(应用进程冲突严重)的情形,CAS自旋的概率会比较大,从而浪费更多的CPU资源,强度低于synchronized。

AQS,非阻塞数据价值形式和原子变量类(java.util.concurrent.atomic包中的类),并与非 concurrent包中的基础类与非 使用并与非 模式来实现的,而concurrent包中的高层类又是依赖于并与非 基础类来实现的。从整体来看,concurrent包的实现示意图如下:

锁存在的现象

JAVA对CAS的支持:在JDK1.5 中新增 java.util.concurrent (J.U.C)就说 建立在CAS之上的。相对于对于 synchronized 并与非 阻塞算法,CAS是非阻塞算法的并与非 常见实现。某些某些J.U.C在性能上有了很大的提升。

1、对于资源竞争较少(应用进程冲突较轻)的情形,使用synchronized同步锁进行应用进程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;而CAS基于硬件实现,不并能 进入内核,不并能 切换应用进程,操作自旋几率较少,为甚让能非要获得更高的性能。

乐观锁与悲观锁

悲观锁机制存在以下现象:  

为甚让JVM不为甚让老会 在单应用进程情形下运行,那样强度太差了。为甚让在给十个 对象分配内存的刚刚 与非 原子性的操作,为宜并能 以下几步:查找空闲列表、分配内存、修改空闲列表等等,这是不安全的。处理并发时的安全现象与非 并与非 策略:





乐观锁:顾名思义,就说 很乐观,每次去拿数据的刚刚 都认为别人不让修改,某些某些不让上锁,为甚让在更新的刚刚 会判断一下在此期间别人有没有 去更新并与非 数据,能非要使用版本号等机制。乐观锁适用于多读的应用类型,另一十个 能非要提高吞吐量,像数据库提供的同类于write_condition机制,确实与非 提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就说 使用了乐观锁的并与非 实现方法 CAS实现的。

以 java.util.concurrent 中的 AtomicInteger 为例,看一下在不使用锁的情形下是怎么可以保证应用进程安全的。主要理解 getAndIncrement 方法 ,该方法 的作用为宜 ++i 操作。

乐观锁

原文发布时间为:2018-07-05

本文来自云栖社区合作协议伙伴“Java架构沉思录”,了解相关信息能非要关注“Java架构沉思录”。



自旋CAS(不成功,就老会 循环执行,直到成功)为甚让长时间不成功,会给CPU带来非常大的执行开销。为甚让JVM能支持处理器提供的pause指令没有 强度会有一定的提升,pause指令有十个 作用,第一它能非要延迟流水线执行指令(de-pipeline),使CPU不让消耗太少的执行资源,延迟的时间取决于具体实现的版本,在某些处理器上延迟时间是零。第二它能非要处理在退出循环的刚刚 因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行强度。

乐观锁的并与非 实现方法 -CAS(Compare and Swap 比较并交换):

CAS是乐观锁技术,当多个应用进程尝试使用CAS一起去更新同十个 变量时,非要其中十个 应用进程能更新变量的值,而其它应用进程都失败,失败的应用进程并非会被挂起,就说 被告知这次竞争中失败,并能非要再次尝试。   

此时轮到应用进程T1执行CAS操作,检测发现栈顶仍为A,某些某些CAS成功,栈顶变为B,但实际上B.next为null,某些某些此时的情形变为:

concurrent包的实现

首先,new object()执行的刚刚 ,并与非 对象并能 多大的空间,确实是为甚让取舍的,为甚让java中的各种数据类型,占用多大的空间与非 固定的(对其原理不清楚的请自行Google)。没有 接下来的工作就说 在堆中找出没有 一块空间用于存放并与非 对象。

当对十个 共享变量执行操作时,当当我们 歌词 都能非要使用循环CAS的方法 来保证原子操作,为甚让对多个共享变量操作时,循环CAS就无法保证操作的原子性,并与非 刚刚 就能非要用锁,为甚让有十个 取巧的方法 ,就说 把多个共享变量合并成十个 共享变量来操作。比如有十个 共享变量i=2,j=a,合并一下ij=2a,为甚让用CAS来操作ij。从Java1.5开始英语 JDK提供了AtomicReference类来保证引用对象之间的原子性,我就把多个变量中放十个 对象里来进行CAS操作。

CAS缺点:

JVM中的CAS(堆中对象的分配) 



现有十个 用单向链表实现的堆栈,栈顶为A,这时应用进程T1为甚让知道A.next为B,为甚让希望用CAS将栈顶替换为B:head.compareAndSet(A,B);在T1执行上方这条指令刚刚 ,应用进程T2介入,将A、B出栈,再pushD、C、A,此时堆栈价值形式如下图,而对象B此时存在游离情形:

如上方源代码所示,应用进程会根据当前处理器的类型来决定是与非 为cmpxchg指令去掉 lock前缀。为甚让应用进程是在多处理器上运行,就为cmpxchg指令去掉 lock前缀(lock cmpxchg)。反之,为甚让应用进程是在单处理器上运行,就省略lock前缀(单处理器自身会维护单处理器内的顺序一致性,不并能 lock前缀提供的内存屏障效果)。



乐观锁( Optimistic Locking)在上文为甚让说过了,确实就说 并与非 思想。相对悲观锁而言,乐观锁假设认为数据一般情形下不让产生并发冲突,某些某些在数据进行提交更新的刚刚 ,才会正式对数据是与非 产生并发冲突进行检测,为甚让发现并发冲突了,则让返回用户错误的信息,让用户决定怎么可以去做。

这里再强调一下,乐观锁是并与非 思想。CAS是并与非 思想的并与非 实现方法 。

上方提到的乐观锁的概念中确实为甚让阐述了它的具体实现细节:主要就说 十个 步骤:冲突检测和数据更新。确实现方法 有并与非 比较典型的就说 Compare and Swap ( CAS )。

悲观锁:老会 假设最坏的情形,每次去拿数据的刚刚 都认为别人会修改,某些某些每次在拿数据的刚刚 与非 上锁,另一十个 别人想拿并与非 数据就会阻塞直到它拿到锁。传统的关系型数据库上方就用到了某些某些并与非 锁机制,比如行锁,表锁等,读锁,写锁等,与非 在做操作刚刚 先上锁。再比如Java上方的同步原语synchronized关键字的实现也是悲观锁。

Java调用new object()会创建十个 对象,并与非 对象会被分配到JVM的堆中。没有 并与非 对象到底是为甚会么会在堆中保存的呢?

CAS 操作带有有十个 操作数 —— 并能 读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。为甚让内存位置V的值与预期原值A相匹配,没有 处理器会自动将该位置值更新为新值B。为甚让处理器不做任何操作。无论哪种情形,它与非 在 CAS 指令刚刚 返回该位置的值。(在 CAS 的某些特殊情形下将仅返回 CAS 是与非 成功,而不提取当前值。)CAS 有效地说明了“ 我认为位置 V 应该带有值 A;为甚让带有该值,则将 B 中放并与非 位置;为甚让,并非更改该位置,只告诉我并与非 位置现在的值即可。 ”这确实和乐观锁的冲突检查+数据更新的原理是一样的。

在没有 锁的机制下,字段value要借助volatile原语,保证应用进程间的数据是可见性。另一十个 在获取变量的值的刚刚 并能直接读取。为甚让来看看 ++i 是为甚会么会做到的。getAndIncrement 采用了CAS操作,每次从内存中读取数据为甚让将此数据和 +1 后的结果进行CAS操作,为甚让成功就返回结果,为甚让重试直到成功为止。而 compareAndSet 利用JNI(Java Native Interface)来完成CPU指令的操作:

补充:synchronized在jdk1.6刚刚 ,为甚让改进优化。synchronized的底层实现主要依靠Lock-Free的队列,基本思路是自旋后阻塞,竞争切换后继续竞争锁,稍微牺牲了公平性,但获得了高吞吐量。在应用进程冲突较少的情形下,能非要获得和CAS同类的性能;而应用进程冲突严重的情形下,性能远高于CAS。

Java的CAS会使用现代处理器上提供的高效机器级别原子指令,并与非 原子指令以原子方法 对内存执行读-改-写操作,这是在多处理器中实现同步的关键(从本质上来说,并能支持原子性读-改-写指令的计算机器,是顺序计算图灵机的异步等价机器,为甚让任何现代的多处理器与非 去支持并与非 能对内存执行原子性读-改-写操作的原子指令)。一起去,volatile变量的读/写和CAS能非要实现应用进程之间的通信。把并与非 价值形式整合在一起去,就形成了整个concurrent包得以实现的基石。为甚当当我们 歌词 都都仔细分析concurrent包的源代码实现,会发现十个 通用化的实现模式:

CAS原理:CAS通过调用JNI的代码实现的。而compareAndSwapInt就说 借助C来调用CPU底层指令实现的。下面从分析比较常用的CPU(intel x86)来解释CAS的实现原理。下面是sun.misc.Unsafe类的compareAndSwapInt()方法 的源代码:

Java在JDK1.5刚刚 与非 靠synchronized关键字保证同步的,并与非 通过使用一致的锁定协议来协调对共享情形的访问,能非要确保无论哪个应用进程持有共享变量的锁,都采用独占的方法 来访问并与非 变量。这就说 并与非 独占锁,独占锁确实就说 并与非 悲观锁,某些某些能非要说 synchronized 是悲观锁。

对比于悲观锁的并与非 现象,另一十个 更加有效的锁就说 乐观锁。确实乐观锁就说 :每次不加锁就说 假设没有 并发冲突而去完成某项操作,为甚让为甚让并发冲突失败就重试,直到成功为止。

没有 比较this == expect,替换this = update,compareAndSwapInt实现这俩个步骤的原子性呢? 参考CAS的原理。

为甚让java的CAS一起去具有 volatile 读和volatile写的内存语义,为甚让Java应用进程之间的通信现在有了下面并与非 方法 :

在单应用进程的情形下,一般有并与非 分配策略:

其中堆栈中非要B十个 元素,C和D组成的链表不再存在于堆栈中,平白无故就把C、D丢掉了。从Java1.5开始英语 JDK的atomic包里提供了十个 类AtomicStampedReference来处理ABA现象。并与非 类的compareAndSet方法 作用是首先检查当前引用是与非 等于预期引用,为甚让当前标志是与非 等于预期标志,为甚让全部相等,则以原子方法 将该引用和该标志的值设置为给定的更新值。

CAS

虚拟机是与非 使用TLAB,能非要通过-XX:+/-UseTLAB参数来进行配置(jdk5及刚刚 的版本默认是启用TLAB的)。