0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

锁实现的基本原理

Android编程精选 来源:Android编程精选 2023-05-29 10:11 次阅读

01 为什么要用锁?

锁-是为了解决并发操作引起的脏读、数据不一致的问题。

02 锁实现的基本原理

2.1、volatile

Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。

volatile在多处理器开发中保证了共享变量的“ 可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。

8bdf22e2-fd52-11ed-90ce-dac502259ad0.jpg202209192321367221.png

结论:如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。

2.2、synchronized

synchronized通过锁机制实现同步。

先来看下利用synchronized实现同步的基础:Java中的每一个对象都可以作为锁。

具体表现为以下3种形式。

对于普通同步方法,锁是当前实例对象。

对于静态同步方法,锁是当前类的Class对象。

对于同步方法块,锁是Synchonized括号里配置的对象。

当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。

2.2.1 synchronized实现原理

synchronized是基于Monitor来实现同步的。

Monitor从两个方面来支持线程之间的同步:

互斥执行

协作

1、Java 使用对象锁 ( 使用 synchronized 获得对象锁 ) 保证工作在共享的数据集上的线程互斥执行。

2、使用 notify/notifyAll/wait 方法来协同不同线程之间的工作。

3、Class和Object都关联了一个Monitor。

8bfd7490-fd52-11ed-90ce-dac502259ad0.jpg202209192321382042.png

Monitor 的工作机理

线程进入同步方法中。

为了继续执行临界区代码,线程必须获取 Monitor 锁。如果获取锁成功,将成为该监视者对象的拥有者。任一时刻内,监视者对象只属于一个活动线程(The Owner)

拥有监视者对象的线程可以调用 wait() 进入等待集合(Wait Set),同时释放监视锁,进入等待状态。

其他线程调用 notify() / notifyAll() 接口唤醒等待集合中的线程,这些等待的线程需要重新获取监视锁后才能执行 wait() 之后的代码。

同步方法执行完毕了,线程退出临界区,并释放监视锁。

参考文档:https://www.ibm.com/developerworks/cn/java/j-lo-synchronized

2.2.2 synchronized具体实现

1、同步代码块采用monitorenter、monitorexit指令显式的实现。

2、同步方法则使用ACC_SYNCHRONIZED标记符隐式的实现。

通过实例来看看具体实现:

8c2173ea-fd52-11ed-90ce-dac502259ad0.jpg202209192321396333.png

javap编译后的字节码如下:

8c607a86-fd52-11ed-90ce-dac502259ad0.jpg202209192321405204.png

monitorenter

每一个对象都有一个monitor,一个monitor只能被一个线程拥有。当一个线程执行到monitorenter指令时会尝试获取相应对象的monitor,获取规则如下:

如果monitor的进入数为0,则该线程可以进入monitor,并将monitor进入数设置为1,该线程即为monitor的拥有者。

如果当前线程已经拥有该monitor,只是重新进入,则进入monitor的进入数加1,所以synchronized关键字实现的锁是可重入的锁。

如果monitor已被其他线程拥有,则当前线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor。

monitorexit

只有拥有相应对象的monitor的线程才能执行monitorexit指令。每执行一次该指令monitor进入数减1,当进入数为0时当前线程释放monitor,此时其他阻塞的线程将可以尝试获取该monitor。

2.2.3 锁存放的位置

锁标记存放在Java对象头的Mark Word中。

8c814018-fd52-11ed-90ce-dac502259ad0.jpg202209192321419575.png

Java对象头长度

8cb62260-fd52-11ed-90ce-dac502259ad0.jpg202209192321427846.png

32位JVM Mark Word 结构

8cd20d68-fd52-11ed-90ce-dac502259ad0.jpg202209192321437957.png

32位JVM Mark Word 状态变化

8d144872-fd52-11ed-90ce-dac502259ad0.jpg202209192321457398.png

64位JVM Mark Word 结构

2.2.3 synchronized的锁优化

JavaSE1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”。

在JavaSE1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。

锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。

偏向锁:

无锁竞争的情况下为了减少锁竞争的资源开销,引入偏向锁。

8d39aebe-fd52-11ed-90ce-dac502259ad0.jpg202209192321466679.png

轻量级锁:

轻量级锁所适应的场景是线程交替执行同步块的情况。

8d39aebe-fd52-11ed-90ce-dac502259ad0.jpg2022091923214830110.png

锁粗化 (Lock Coarsening):也就是减少不必要的紧连在一起的unlock,lock操作,将多个连续的锁扩展成一个范围更大的锁。

锁消除 (Lock Elimination):锁削除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行削除。

适应性自旋Adaptive Spinning):自适应意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而它将允许自旋等待持续相对更长的时间,比如100个循环。另一方面,如果对于某个锁,自旋很少成功获得过,那在以后要获取这个锁时将可能省略掉自旋过程,以避免浪费处理器资源。

2.2.4 锁的优缺点对比

8d855972-fd52-11ed-90ce-dac502259ad0.jpg2022091923214950111.png

2.3、CAS

CAS,在Java并发应用中通常指CompareAndSwap或CompareAndSet,即比较并交换。

1、CAS是一个原子操作,它比较一个内存位置的值并且只有相等时修改这个内存位置的值为新的值,保证了新的值总是基于最新信息计算的,如果有其他线程在这期间修改了这个值则CAS失败。CAS返回是否成功或者内存位置原来的值用于判断是否CAS成功。

2、JVM中的CAS操作是利用了处理器提供的CMPXCHG指令实现的。

优点:

竞争不大的时候系统开销小。

缺点:

循环时间长开销大。

ABA问题。

只能保证一个共享变量的原子操作。

03 Java中的锁实现

3.1、队列同步器(AQS)

队列同步器AbstractQueuedSynchronizer(以下简称同步器),是用来构建锁或者其他同步组件的基础框架。

3.1.1、它使用了一个int成员变量表示同步状态。

8da42992-fd52-11ed-90ce-dac502259ad0.jpg2022091923215056212.png

3.1.2、通过内置的FIFO双向队列来完成获取锁线程的排队工作。

同步器包含两个节点类型的应用,一个指向头节点,一个指向尾节点,未获取到锁的线程会创建节点线程安全(compareAndSetTail)的加入队列尾部。同步队列遵循FIFO,首节点是获取同步状态成功的节点。

8dc0509a-fd52-11ed-90ce-dac502259ad0.jpg2022091923215155913.png

未获取到锁的线程将创建一个节点,设置到尾节点。如下图所示:

8def1d12-fd52-11ed-90ce-dac502259ad0.jpg2022091923215254714.png

首节点的线程在释放锁时,将会唤醒后继节点。而后继节点将会在获取锁成功时将自己设置为首节点。如下图所示:

8e0e3d14-fd52-11ed-90ce-dac502259ad0.jpg2022091923215350515.png

3.1.3、独占式/共享式锁获取

独占式:有且只有一个线程能获取到锁,如:ReentrantLock;

共享式:可以多个线程同时获取到锁,如:CountDownLatch;

独占式

每个节点自旋观察自己的前一节点是不是Header节点,如果是,就去尝试获取锁。

8e49e8f0-fd52-11ed-90ce-dac502259ad0.jpg2022091923215449316.png

独占式锁获取流程:

8e6dfede-fd52-11ed-90ce-dac502259ad0.jpg2022091923215549017.png

共享式:

共享式与独占式的区别:

8ebfc534-fd52-11ed-90ce-dac502259ad0.jpg2022091923215682218.png

共享锁获取流程:

8ee1abe0-fd52-11ed-90ce-dac502259ad0.jpg2022091923215785919.png

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    19259

    浏览量

    229653
  • 数据
    +关注

    关注

    8

    文章

    7002

    浏览量

    88943
  • 编程语言
    +关注

    关注

    10

    文章

    1942

    浏览量

    34707

原文标题:Java中的锁原理、锁优化、CAS、AQS,看这篇就对了!

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    步进电机基本原理

    本帖最后由 eehome 于 2013-1-5 09:48 编辑 步进电机基本原理
    发表于 08-16 16:17

    串联谐振逆变器的基本原理

    串联谐振通常伴有逆变器。该组合称为串联谐振逆变器。什么是基本原理?让我简要介绍串联谐振逆变器的一些基本原理。]首先给你看一张图片:
    发表于 11-07 10:21

    电流检测电阻的基本原理

    电流检测电阻的基本原理简单采样电路的实现
    发表于 01-29 06:26

    电机转动的基本原理是什么?

    电机转动的基本原理是什么?电机运动的基本原则有哪些?
    发表于 07-21 07:59

    线性电源的基本原理是什么

    多路线性电源 AC-DC稳压电源 低纹波电源 可调线性电源 原理图PCB目录多路线性电源 AC-DC稳压电源 低纹波电源 可调线性电源 原理图PCB基本原理芯片选型原理图&3D-PCB具体
    发表于 07-30 07:47

    无线充电的基本原理是什么

    一 、无线充电基本原理无线充电的基本原理就是我们平时常用的开关电源原理,区别在于没有磁介质耦合,那么我们需要利用磁共振的方式提高耦合效率,具体方法是在发送端和接收端线圈串并联电容,是发送线圈处理谐振
    发表于 09-15 06:01

    RAID技术的基本原理是什么

    RAID技术的基本原理是什么?RAID技术有哪几个优势?
    发表于 10-14 12:01

    PWM控制的基本原理是什么

    PWM控制的基本原理是什么?如何让逆变器输出为等幅矩形波呢?如何实现低通滤波器呢?
    发表于 10-22 07:06

    DA0832实现DA转换的基本原理是什么

    1、描述DA0832实现DA转换的基本原理1、DAC0832是一个八位D/A转换器,D/A转换电路是一个R-2RT型电阻网络,可实现8位数据的转换。2、数据总线——DI7~DI0:转换数据输入控制
    发表于 11-26 08:27

    串口通信的基本原理是什么?

    同步通信和异步通信的区别是什么?串口通信的基本原理是什么?
    发表于 12-13 06:46

    PDB基本原理是什么

    PDB基本原理1.Programmable delay block (PDB)的逻辑框图2.核心功能实现2.1.输入trigger的选择2.2.trigger和pre-trigger的输出
    发表于 01-13 08:29

    步进马达基本原理

    步进马达基本原理步进马达基本原理步进马达基本原理
    发表于 11-30 11:55 8次下载

    Redis Cluster的基本原理实现细节

    Redis Cluster的基本原理和架构 Redis Cluster是分布式Redis的实现。随着Redis版本的更替,以及各种已知bug的fixed,在稳定性和高可用性上有了很大的提升和进步
    发表于 09-28 19:09 0次下载
    Redis Cluster的<b class='flag-5'>基本原理</b>及<b class='flag-5'>实现</b>细节

    分布式基本原理和案例实现

    前面我们有聊过乐观和悲观实现,均是对于单体架构的场景下的实现。那么现在我们来总结看下分布式情况下如何实现
    的头像 发表于 07-01 14:53 3328次阅读
    分布式<b class='flag-5'>锁</b>的<b class='flag-5'>基本原理</b>和案例<b class='flag-5'>实现</b>

    RNN的基本原理实现

    RNN,即循环神经网络(Recurrent Neural Network),是一种特殊类型的人工神经网络,专门设计用于处理序列数据,如文本、语音、视频等。以下是对RNN基本原理实现的介绍: 一
    的头像 发表于 11-15 09:49 403次阅读