Java中初始是使用mutex互斥锁,因为互斥锁是会线程等待挂起,而对获取锁后的操作时间比较短暂的应用场景来说,这样的锁会让竞争锁的线程不停的park,unpark 的操作,这样的系统的调用性能是非常糟糕的,为了提高锁的性能,java 在6 默认使用了自旋锁。
在Linux中本身就已经提供了自旋锁的系统调用,在glibc-2.9中就有它的比较简单的实现方法
通过总线锁把参数-1保证了减法的原子性,如果减后的值是(0)的代表获得锁,其他线程的线程自旋直到参数变成初始值(1),继续竞争锁,直到获得这把锁。
Java 并没有使用系统自带的自旋锁,自己重写了自旋锁的逻辑,并且增加了自旋的次数的控制。详细见-XX:+UseSpinning 和-XX:PreBlockSpin=xx
让我们具体来看是如何实现的,注意这是mutex锁中所实现的lock,而并不是synchinized 的锁的spin lock的实现(这个你可以参考synchronizer.cpp里的方法TrySpin_VaryDuration)
a. os::is_MP() 判断系统是否是多核的系统,在单核下,自旋锁是没有意义的。
b. CASPTR 使用了 Atomic::cmpxchg_ptr 原子语义 cmpxchg 比较替换,如果比较的值相等就替换成需要的值并且返回去比较的值,如果不相同返回被比较的值的内容。
在这里的语义是比较_LockWord.FullWord 和 _Lockword 的值是否相同,如果相同就把_Lockword 的值置换成v|_LBIT(_LBIT的值是1)。
自旋锁的逻辑:判断_LockWord.FullWord bit 0 是否是0,如果是0代表没有占有锁,那就尝试去占有锁,通过原子替换置bit0 为1,如果置换成功那么代表拥有锁,没有则进入自旋。
SpinPause () 函数
在linux_x86 64位机器上 定义了
.globl SpinPause
.align 16
.type SpinPause,@function
SpinPause:
rep
nop
movq $1, %rax
ret
主要在rep, nop 的指令经过编译器后的指令是pause,是用于提高cpu性能的,在官方上描述pase指令是为了避免memory order violation ,有种说法就是cpu是流水线的处理指令的,当原子指令store的时候,而如果有线程同时也在load他的值,那么load 必须等到store 执行成功,这样cpu就无法进行流水线作业了。但我更觉的这是个加强版的nop 也就是多增加几个空的机器周期,一来省电,二来本身spin lock就需要cpu空运行,并且不需要访问内存。
c. SafepointSynchronize::do_call_back()这是一个安全点,提供一个停止自旋锁的切入点,比如vm thread,在做线程dump, 内存 dump的时候,是需要让 自旋锁提前停止的。
d. if (Probes > SpinMax) return 0 ; 当大于自旋的次数的时候,自旋自动退出,也就是前面所说的参数-XX:PreBlockSpin
最后这里还有个比较有意思的方法MarsagliaXORV (rv) ; 是算随机数的,不清楚为什么java让cpu自旋的过程中计算随机数的意义何在,为了不让cpu空转?感觉用spinpase 更合理一点。
分享到:
相关推荐
2. **SpinLock(自旋锁)**:最基础的自旋锁实现,通常不保证公平性。线程在尝试获取锁失败后,会持续自旋检查锁的状态,直到成功。不过,有些高级的自旋锁实现可以加入公平策略,例如采用FIFO(先进先出)原则。`...
Redis中的分布式锁实现通常基于`SETNX`命令或`SET`命令的`nx`与`ex`组合。`SETNX`命令用于设置键值,但如果键已经存在,则不执行任何操作,这可以确保锁的互斥性。`SET key value EX timeout NX`则同时设置了超时...
本文主要讨论了四种锁类型:乐观锁、悲观锁、自旋锁以及Java中的synchronized同步锁,并深入解析了synchronized锁的内部机制,包括其核心组件、实现方式以及锁的状态。 1. **乐观锁**:乐观锁假设在多线程环境下,...
例如,上述代码展示了一个简单的自旋锁实现,通过`AtomicReference`的`compareAndSet`方法来尝试获取和释放锁。当线程尝试获取锁时,如果`compareAndSet`操作成功,说明锁未被持有,线程就能获取到锁;否则,线程会...
深入讲解CAS自旋锁的实现机理和原理 CAS(Compare and Swap)是实现自旋锁或乐观锁的核心操作,它的出现是为了解决原子操作的问题。在多线程环境下,原子操作是保证线程安全的重要手段。CAS操作的实现很简单,就是...
这个简单的自旋锁实现利用了`AtomicReference`的CAS操作来尝试获取或释放锁。在`lock()`方法中,线程会不断地尝试用当前线程替换`AtomicReference`中的`null`,直到成功为止,即获得了锁。在`unlock()`方法中,释放...
深入理解Java自旋锁 Java自旋锁是一种锁机制,用于解决多线程之间的变量同步问题。自旋锁的实现是基于CAS(Compare And Swap)算法的,它可以在不使用锁的情况下实现多线程之间的变量同步。 自旋锁的定义是指当一...
本文将详细介绍Java中包括乐观锁、悲观锁、自旋锁、可重入锁、读写锁等多种锁机制的概念、特点、应用场景及其优化技术。 1. 乐观锁与悲观锁 乐观锁与悲观锁反映了对数据并发访问策略的不同预期。乐观锁假设数据通常...
在Java中,常见的乐观锁实现是无锁编程,如使用原子类(AtomicInteger、AtomicLong等)中的CAS(Compare and Swap)算法。悲观锁则假设在读取数据时会有其他线程修改,所以在读取时即加锁,如`synchronized`关键字和...
总结来说,`synchronized`锁机制在Java中通过多种方式实现了线程同步,包括自旋锁、自适应自旋锁、轻量锁和偏向锁,这些机制在不同程度上减少了锁的开销,提高了并发性能。在实际编程中,了解这些机制有助于编写出...
Java中,`java.util.concurrent.atomic`包下的原子变量类如AtomicInteger、AtomicLong等利用CAS(Compare and Swap)算法实现了乐观锁。 - **悲观锁**假设并发环境下数据频繁被修改,因此在读取时就会上锁,确保...
在Java中,锁的机制主要可以分为乐观锁和悲观锁两大类,此外还包括自旋锁、Synchronized同步锁和可重入锁等,下面将详细介绍这些核心知识点。 乐观锁是一种基于“我认为数据不会经常发生冲突”的假设而设计的锁策略...
自旋锁SpinLock唉….刚写完了!别白嫖啊,点赞关注,给你们福利啊~~转载请标注! 好兄弟们,不会真有人看不懂CAS吧?反正我是没看懂… 一. CAS是什么? import java.util.concurrent.atomic.AtomicInteger; /** * 1. CAS...
总的来说,Java的`synchronized`通过对象头的Mark Word和Monitor对象实现了线程安全的同步机制,同时引入了偏向锁、轻量级锁和自旋锁等优化手段,以平衡性能和线程安全性。理解这些锁的工作原理对于编写高性能的并发...
重量级锁是Java中最传统的锁实现,依赖于操作系统级别的互斥量,导致较大的上下文切换开销。当轻量级锁的CAS操作失败,或者偏向锁发现有线程竞争时,锁会升级为重量级锁,所有等待的线程都会被挂起,直到持有锁的...
以上是对给定文件中提到的关键知识点的详细解析,涵盖了Java编程的基础概念、高级特性以及Web开发中的一些核心原理。这些知识点不仅对于准备华为或其他公司IT岗位面试的候选人来说非常重要,同时也是Java开发者日常...
Java 中的锁分类可以分为多种类型,包括公平锁、非公平锁、可重入锁、独享锁、共享锁、互斥锁、读写锁、乐观锁、悲观锁、分段锁、偏向锁、轻量级锁、重量级锁、自旋锁等。这些锁的分类并不是指锁的状态,有的指锁的...
例如,上述代码中的自旋锁模拟展示了不可重入锁的实现。 3. **独享锁 / 共享锁** - **独享锁**(互斥锁) 只允许一个线程访问共享资源,如`ReentrantLock`的独占模式。 - **共享锁**(读写锁)允许多个线程同时...