我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java中锁的实现原理和实例用法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java中锁的实现原理和实例用法

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

一、为什么要用锁?

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

二、锁实现的基本原理

2.1、volatile

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

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

Java中锁的实现原理和实例用法

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

2.2、synchronized

synchronized通过锁机制实现同步。

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

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

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

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

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

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

2.2.1 synchronized实现原理

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

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

  • 互斥执行

  • 协作

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

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

Class和Object都关联了一个Monitor。

Java中锁的实现原理和实例用法

Monitor 的工作机理

  • 线程进入同步方法中。

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

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

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

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

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

2.2.2 synchronized具体实现

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

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

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

Java中锁的实现原理和实例用法

javap编译后的字节码如下:

Java中锁的实现原理和实例用法

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中。

Java中锁的实现原理和实例用法

Java对象头长度

Java中锁的实现原理和实例用法

32位JVM Mark Word 结构

Java中锁的实现原理和实例用法

32位JVM Mark Word 状态变化

Java中锁的实现原理和实例用法

64位JVM Mark Word 结构

2.2.3 synchronized的锁优化

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

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

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

偏向锁:

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

Java中锁的实现原理和实例用法

轻量级锁:

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

Java中锁的实现原理和实例用法

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

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

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

2.2.4 锁的优缺点对比

Java中锁的实现原理和实例用法

2.3、CAS

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

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

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

优点:

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

缺点:

  • 循环时间长开销大。

  • ABA问题。

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

三、Java中的锁实现

3.1、队列同步器(AQS)

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

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

Java中锁的实现原理和实例用法

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

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

Java中锁的实现原理和实例用法

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

Java中锁的实现原理和实例用法

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

Java中锁的实现原理和实例用法

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

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

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

独占式

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

Java中锁的实现原理和实例用法
  • 独占式锁获取流程:

Java中锁的实现原理和实例用法

共享式:

  • 共享式与独占式的区别:

Java中锁的实现原理和实例用法
  • 共享锁获取流程:

Java中锁的实现原理和实例用法

四、锁的使用用例

4.1、ConcurrentHashMap的实现原理及使用

Java中锁的实现原理和实例用法

ConcurrentHashMap类图

Java中锁的实现原理和实例用法

ConcurrentHashMap数据结构

结论:ConcurrentHashMap使用的锁分段技术。首先将数据分成一段一段地存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java中锁的实现原理和实例用法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java中锁的实现原理和实例用法

这篇文章主要介绍“Java中锁的实现原理和实例用法”,在日常操作中,相信很多人在Java中锁的实现原理和实例用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中锁的实现原理和实例用法”的疑惑有所帮助!
2023-06-16

Java 重入锁实现的原理究竟是什么?(java重入锁实现的原理是什么)

在Java编程中,重入锁(ReentrantLock)是一种非常重要的同步机制,它在实现线程安全的同时,提供了比synchronized关键字更灵活的控制方式。本文将深入探讨Java重入锁实现的原理,帮助你更好地理解和使用这一机制。一、重入锁的基本概
Java 重入锁实现的原理究竟是什么?(java重入锁实现的原理是什么)
Java2024-12-21

redis分布式锁的实现原理实例分析

这篇文章主要介绍了redis分布式锁的实现原理实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇redis分布式锁的实现原理实例分析文章都会有所收获,下面我们一起来看看吧。首先,为了确保分布式锁可用,我们至
2023-06-29

Java实现读写锁的原理是什么

本文小编为大家详细介绍“Java实现读写锁的原理是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java实现读写锁的原理是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。读/写锁Java实现首先我们总结一
2023-06-29

mysql中Innodb 行锁实现原理

目录一、Innodb行锁的实现二、场景分析三、特殊场景一、Innodb行锁的实现【1】Innodb的行锁是通过给索引的索引项加锁来实现的【2】Innodb按照辅助索引进行数据操作时,辅助索引和主键索引都将锁定指定的索引项【3】通过索引
mysql中Innodb 行锁实现原理
2024-10-21

java Semaphore共享锁实现原理解析

这篇文章主要为大家介绍了Semaphore共享锁实现原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-09

Redis常见分布锁的原理和实现

目录前言基于数据库悲观锁实现原理具体实现乐观锁简介实现原理具体实现Redis实现分布式锁Zooker实现分布式锁加锁过程释放锁的过程异常场景分析具体实现Zookpeer实现分布式锁实现库存扣减总结前言Java中的锁主要包括synchron
2022-08-18

javaReentrantLock条件锁实现原理示例详解

这篇文章主要为大家介绍了javaReentrantLock条件锁实现原理示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-09

详解Java ReentrantReadWriteLock读写锁的原理与实现

ReentrantReadWriteLock读写锁是使用AQS的集大成者,用了独占模式和共享模式。本文和大家一起理解下ReentrantReadWriteLock读写锁的实现原理,需要的可以了解一下
2022-11-13

Mysql行锁和表锁的实现示例

目录行锁和表锁加索引的影响注意事项常见面试题什么是表锁和行锁?它们有什么区别?mysql中的表锁有哪些类型?行锁是如何工作的?什么情况下会触发行锁?如何在MySQL中手动获取行锁?行锁和表锁在性能上有什么区别?如何优化数据库并发性能?举例说
Mysql行锁和表锁的实现示例
2024-08-19

Java中的布隆过滤器原理实现和应用

Java中的布隆过滤器是一种基于哈希函数的数据结构,能够高效地判断元素是否存在于一个集合中。它广泛应用于缓存、网络协议、数据查询等领域,在提高程序性能和减少资源消耗方面具有显著优势
2023-05-17

Semaphore的原理和实现方法

本篇内容介绍了“Semaphore的原理和实现方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Semaphore数据结构// Go 语言中
2023-06-15

浅析Redis中红锁RedLock的实现原理

RedLock是一个分布式锁服务,通过同时向多个Redis实例发送请求来获取锁。如果从超过一半的实例获取了抢险值,则客户端成功获取锁。RedLock的优点包括高容错性、可扩展性和轻量级。缺点是网络开销、复杂性和受最慢实例性能影响。RedLock适用于需要高容错性互斥锁的分布式系统,如分布式缓存排他访问和数据库并发控制。
浅析Redis中红锁RedLock的实现原理
2024-04-02

详解Java中跳跃表的原理和实现

跳跃表(Skiplist)是有序链表的扩展,简称跳表,它在原有的有序链表上增加了多级索引,通过索引来实现快速查找,实质上是一种可以进行二分查找的有序链表。本文主要为大家介绍了跳跃表的原理和实现,需要的可以参考一下
2022-12-27

iOS中读写锁的简单实现方法实例

目录废话开篇思考一、对于锁的类型的理解思考二、读写锁的实现逻辑思考三、简单封装读写锁,满足读写逻辑总结废话开篇 iOS 下的多线程的技术的应用衍生出了锁的机制,试想,如果 iOS 下没有多线程的概念,所有的代码都会在同步环境下执行,那么,也
2022-06-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录