千家信息网

Java中的锁有哪些

发表于:2024-11-20 作者:千家信息网编辑
千家信息网最后更新 2024年11月20日,这篇文章主要介绍"Java中的锁有哪些",在日常操作中,相信很多人在Java中的锁有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Java中的锁有哪些"的疑惑有所帮
千家信息网最后更新 2024年11月20日Java中的锁有哪些

这篇文章主要介绍"Java中的锁有哪些",在日常操作中,相信很多人在Java中的锁有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Java中的锁有哪些"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、锁的类型

Java中的锁从宏观来分,分为悲观锁、和乐观锁。

乐观锁

乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。

java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。

悲观锁

悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。java中的悲观锁就是synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock。

二、Java线程阻塞的代价

Java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就需要操作系统介入,需要在用户态与核心态之间切换,这种切换会消耗大量的系统资源,因为用户态与内核态都有各自专用的内存空间,专用的寄存器等,用户态切换至内核态需要传递给许多变量、参数给内核,内核也需要保护好用户态在切换时的一些寄存器值、变量等,以便内核态调用结束后切换回用户态继续工作。

  1. 如果线程状态切换是一个高频操作时,这将会消耗很多CPU处理时间;

  2. 如果对于那些需要同步的简单的代码块,获取锁挂起操作消耗的时间比用户代码执行的时间还要长,这种同步策略的选择就很不明智。

synchronized会导致争用不到锁的线程进入阻塞状态,所以说它是Java语言中一个重量级的同步操纵,被称为重量级锁,为了缓解上述性能问题,JVM从1.5开始,引入了轻量锁与偏向锁,默认启用了自旋锁,他们都属于乐观锁

明确java线程切换的代价,是理解java中各种锁的优缺点的基础之一。

三、markword

markword是java对象数据结构中的一部分,对象的markword和java各种类型的锁密切相关;

markword数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit,它的最后2bit是锁状态标志位,用来标记当前对象的状态,对象的所处的状态,决定了markword存储的内容,如下表所示:

状态标志位存储内容
未锁定01对象哈希码、对象分代年龄
轻量级锁定00指向锁记录的指针
膨胀(重量级锁定)10执行重量级锁定的指针
GC标记11空(不需要记录信息)
可偏向01偏向线程ID、偏向时间戳、对象分代年龄

32位虚拟机在不同状态下markword结构如下所示:

锁状态25bit4bit1bit2bit
23bit2bit是否是偏向锁锁标志位

轻量级锁指向栈中锁记录的指针00


重量级锁指向互斥量(重量级锁)的指针10


GC标记11


偏向锁线程IDEpoch对象分代年龄101
无锁对象的hashCode对象分代年龄0001

小结

前面提到了java的4种锁,他们分别是重量级锁、自旋锁、轻量级锁和偏向锁,不同的锁有不同特点,每种锁只有在其特定的场景下,才会有出色的表现,java中没有哪种锁能够在所有情况下都能有出色的效率,引入这么多锁的原因就是为了应对不同的情况。

重量级锁是悲观锁的一种自旋锁、轻量级锁与偏向锁属于乐观锁。

到此,关于"Java中的锁有哪些"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0