iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java中锁的实现原理和实例用法
  • 582
分享到

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

2023-06-16 16:06:50 582人浏览 八月长安
摘要

这篇文章主要介绍“Java中锁的实现原理和实例用法”,在日常操作中,相信很多人在Java中锁的实现原理和实例用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”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中锁的实现原理和实例用法”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Java中锁的实现原理和实例用法

本文链接: https://www.lsjlt.com/news/284255.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

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

下载Word文档
猜你喜欢
  • Java中锁的实现原理和实例用法
    这篇文章主要介绍“Java中锁的实现原理和实例用法”,在日常操作中,相信很多人在Java中锁的实现原理和实例用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中锁的实现原理和实例用法”的疑惑有所帮助!...
    99+
    2023-06-16
  • redis分布式锁的实现原理实例分析
    这篇文章主要介绍了redis分布式锁的实现原理实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇redis分布式锁的实现原理实例分析文章都会有所收获,下面我们一起来看看吧。首先,为了确保分布式锁可用,我们至...
    99+
    2023-06-29
  • Java实现读写锁的原理是什么
    本文小编为大家详细介绍“Java实现读写锁的原理是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java实现读写锁的原理是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。读/写锁Java实现首先我们总结一...
    99+
    2023-06-29
  • Java方法引用原理实例解析
    目录冗余的Lambda场景问题分析用方法引用改进代码方法引用符通过对象名引用成员方法通过类名称引用静态方法通过super引用成员方法通过this引用成员方法类的构造器引用数组的构造器...
    99+
    2022-11-12
  • java Semaphore共享锁实现原理解析
    目录正文Semaphore内部类及继承关系Semaphore.acquire流程分析(以非公平锁为例)tryAcquireShareddoAcquireSharedInterrupt...
    99+
    2023-01-09
    Semaphore共享锁 java 锁
  • javaReentrantLock条件锁实现原理示例详解
    目录引言条件锁的使用ReentrantLock.newCondition()Condition.awaitCondition.signal引言 在前两篇文章中,我们了解了Reentr...
    99+
    2023-01-09
    java ReentrantLock条件锁 java ReentrantLock
  • 详解Java ReentrantReadWriteLock读写锁的原理与实现
    目录概述原理概述加锁原理图解过程源码解析解锁原理图解过程源码解析概述 ReentrantReadWriteLock读写锁是使用AQS的集大成者,用了独占模式和共享模式。本文和大家一起...
    99+
    2022-11-13
    Java ReentrantReadWriteLock读写锁 Java ReentrantReadWriteLock Java 读写锁
  • JAVA偏向锁的原理与实战
    目录1. 偏向锁的核心原理2. 偏向锁代码演示3. 偏向锁的膨胀与撤销1. 偏向锁的撤销2. 批量重偏向与撤销3. 偏向锁的膨胀总结1. 偏向锁的核心原理 如果不存在线程竞争的一个线...
    99+
    2022-11-13
  • Redis常见分布锁的原理和实现
    目录前言基于数据库悲观锁实现原理具体实现乐观锁简介实现原理具体实现Redis实现分布式锁Zooker实现分布式锁加锁过程释放锁的过程异常场景分析具体实现Zookpeer实现分布式锁实现库存扣减总结前言 Java中的锁主要...
    99+
    2022-08-18
    Redis分布锁原理 Redis分布锁实现
  • Java实现雪花算法的原理和实战教程
    目录 SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应...
    99+
    2022-11-12
  • java LockSupport实现原理示例解析
    目录引言LockSupport常见函数LockSupport.parkLockSupport.unpark引言 前文中了解到AQS借助LockSupport.park和LockSup...
    99+
    2023-01-09
    java LockSupport原理 java LockSupport
  • Java实现雪花算法的原理
    SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分...
    99+
    2022-11-12
  • Java synchronized底层实现原理以及锁优化
    目录一、概述synchronized简介synchronized作用synchronized的使用二、实现原理三、理解Java对象头四、JVM对synchronized的锁优化1、偏...
    99+
    2022-11-13
  • Spring事务的用法示例与实现原理
    本篇内容主要讲解“Spring事务的用法示例与实现原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring事务的用法示例与实现原理”吧!关于事务,简单来说,就是为了保证数据完整性而存在的一...
    99+
    2023-06-16
  • iOS中读写锁的简单实现方法实例
    目录废话开篇思考一、对于锁的类型的理解思考二、读写锁的实现逻辑思考三、简单封装读写锁,满足读写逻辑总结废话开篇 iOS 下的多线程的技术的应用衍生出了锁的机制,试想,如果 iOS 下...
    99+
    2022-06-04
    ios 读写锁
  • GO的锁和原子操作实例分析
    本篇内容介绍了“GO的锁和原子操作实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!锁是什么锁 是用于解决隔离性的一种机制某个协程(线程...
    99+
    2023-07-05
  • redis分布式锁的实现原理
    小编给大家分享一下redis分布式锁的实现原理,希望大家阅读完这篇文章后大所收获,下面让我们一起去探讨吧!分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性。举个不太恰当...
    99+
    2022-10-18
  • golang锁的实现原理是什么
    golang锁的实现原理是通过互斥锁和读写锁来保护共享资源的访问。互斥锁是一种基本的锁机制,用于保护共享资源,使用一个标志位来表示资源是否被占用,当一个goroutine获取到互斥锁后,其他goroutine就会被阻塞,直到该gorouti...
    99+
    2023-12-12
    Golang
  • Semaphore的原理和实现方法
    本篇内容介绍了“Semaphore的原理和实现方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Semaphore数据结构// G...
    99+
    2023-06-15
  • Python实现的堆排序算法原理与用法实例分析
    本文实例讲述了Python实现的堆排序算法。分享给大家供大家参考,具体如下: 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的...
    99+
    2022-06-04
    算法 实例 原理
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作