首页 > 编程语言 >Java 分级锁

Java 分级锁

时间:2024-09-08 23:23:05浏览次数:9  
标签:基于 调用 Java 获取 线程 分级 方法 example

在 JDK 1.8 中,synchronized 关键字的性能得到了显著提升,这主要得益于 JVM 对锁机制进行了一系列优化:锁的分级及其优化路径(大体可以按照下面的路径进行升级:偏向锁 — 轻量级锁 — 重量级锁,锁只能升级,不能降级,所以一旦升级为重量级锁,就只能依靠操作系统进行调度)。


要想了解锁升级的过程,需要先看一下对象在内存里的结构。




在 Java 中,对象的内存布局中包含了 MarkWord、Class Pointer、Instance Data 和 Padding 等部分。而锁的升级过程主要与对象头的 MarkWord 有关。


要知道MarkWord 是对象头中用于存储对象的运行时信息的。在 64 位 JVM 中,MarkWord 的长度为 64 位。在 32 位 JVM 中,MarkWord 的长度为 32 位(如上图)。


偏向锁(Biased Locking)

单线程高效使用锁:在只有一个线程使用锁的情况下,偏向锁效率最高。

获取锁:第一个线程访问同步块时,会检查对象头 Mark Word 的标志位 Tag 是否为 01。如果是,线程将自己的线程 ID 写入 Mark Word,锁进入偏向锁状态。

撤销偏向锁:当其他线程尝试获取锁时,如果 Mark Word 中的线程 ID 不匹配,偏向锁会被撤销,升级为轻量级锁。

适合单线程场景,高效。

轻量级锁

自旋锁获取:参与竞争的线程会在自己的线程栈中生成一个 LockRecord (LR),通过 CAS(自旋)的方式,将锁对象头中的 Mark Word 设置为指向自己的 LR 的指针。设置成功的线程获得锁。

自旋失败:如果自旋多次失败,锁会升级为重量级锁。

适合短期竞争,自旋获取锁。

重量级锁

系统调度:重量级锁会导致线程挂起,进入操作系统内核态,等待操作系统调度,然后再映射回用户态。系统调用的开销很高,锁的膨胀到重量级锁就意味着性能下降。

激烈竞争:如果共享变量竞争激烈,锁会迅速膨胀为重量级锁。如果并发竞争严重,可以使用 -XX:-UseBiasedLocking 禁用偏向锁,可能会有一些性能提升。

适合长期竞争,但性能开销大。

3. 锁升级一览



(二)concurrent 包里面的 Lock

synchronized 是 Java 提供的最基本的同步机制,通过简单易用的语法确保线程安全。然而,随着并发需求的复杂化,Java 的并发包 (java.util.concurrent) 提供了更多高级和高效的并发工具,如 ReentrantLock、ReadWriteLock、Atomic 类等,来应对更复杂的并发场景。在实际开发中,应根据具体情况选择合适的同步机制。现在我们聚焦在Lock进行分析。


1. 锁机制基于线程而不是基于调用(可重入锁)

“这种锁机制基于线程而不是基于调用” 的意思是说,当一个线程持有锁时,它可以在同一个线程的不同调用链中多次获取同一把锁,而不会被阻塞或引发死锁。这是因为锁是跟线程关联的,而不是跟调用栈关联的。


假设有一个对象 example,它有三个同步方法 a、b 和 c,每个方法都被 synchronized 关键字修饰:


package org.zyf.javabasic.thread.lock.opti;

/**

* @program: zyfboot-javabasic

* @description: 锁机制基于线程而不是基于调用

* @author: zhangyanfeng

* @create: 2024-06-07 19:04

**/

public class LockExample {

   public synchronized void a() {

       System.out.println("In method a");

       b();  // 调用 b 方法

   }

   public synchronized void b() {

       System.out.println("In method b");

       c();  // 调用 c 方法

   }

   public synchronized void c() {

       System.out.println("In method c");

   }

   public static void main(String[] args) {

       LockExample example = new LockExample();

       example.a();

   }

}

在 main 方法中,我们调用了 example.a()。在 a 方法内部,又调用了 b 方法,而 b 方法内部又调用了 c 方法。这种调用关系如下:


example.a()

   -> example.b()

       -> example.c()

当线程调用 example.a() 时,由于 a 方法是同步方法,线程必须先获得对象 example 的锁。在 a 方法内部,线程调用 example.b()。虽然 b 方法也是同步方法,但是由于当前线程已经持有了 example 对象的锁,所以它可以继续执行,不需要再次获取锁。类似地,在 b 方法内部,线程调用 example.c() 时,也不需要再次获取锁。


这个过程中锁是跟线程关联的,而不是跟每次调用关联的。一个线程持有锁之后,可以在它的调用栈中多次获取同一把锁,而不需要重新获取锁,也不会被阻塞。


如果 Java 的锁机制不是基于线程的,而是基于每次调用的,那么在上面的示例中,线程在调用 b 方法时会尝试再次获取 example 对象的锁,但是由于它已经持有这个锁,这将导致死锁。因此,基于线程的锁机制(即可重入锁)避免了这种情况,使得一个线程在持有锁时,可以多次获取同一把锁。Java 的 ReentrantLock 类也支持可重入性,将以上synchronized替换成其效果也是一样的。


像上面这样,在并发编程中,可重入锁(Reentrant Lock)指的是一个线程可以多次获得同一把锁。可重入锁的作用在于避免线程死锁,当一个线程已经持有了一个锁,再次请求该锁时可以直接获取,而无需再次等待。这种锁机制基于线程而不是基于调用。


标签:基于,调用,Java,获取,线程,分级,方法,example
From: https://blog.51cto.com/u_16270511/11953436

相关文章

  • Java的并发编程模型同步器
    在Java的并发编程中,同步器(Synchronizer)是一个非常重要的概念,它用于管理多个线程之间的协作,以确保线程间的正确交互和数据的一致性。Java并发包java.util.concurrent中提供了多种同步器,这些同步器主要用于实现锁(Locks)和其他并发原语(ConcurrencyPrimitives)。主要的同步器包括:......
  • 什么是 Java 虚拟机(JVM)?它的主要作用是什么?
    Java虚拟机(JavaVirtualMachine,简称JVM)是运行Java字节码的虚拟机。它是Java平台的一个核心部分,使得Java程序能够在任何安装了JVM的计算机上运行,而无需关心底层的操作系统或硬件差异。JVM为Java应用程序提供了一个安全、高效和可移植的执行环境。JVM的主要作......
  • 走向Java Server Page的第一个网页
    环境配置有关tomcat和jdk的环境配置在上一篇博客已经讲述,存在问题请查看上一篇。开发需求计算1到100的连续和,并将结果显示在一个带有样式的HTML页面中。当这个JSP页面被服务器处理时,Java代码会被执行,计算结果会被嵌入到HTML中,然后发送给客户端浏览器显示。代码实现首先使......
  • JavaScript高级——数据、变量、内存
    1、数据存储在内存中代表特定信息的东西,本质上是010101…….数据的特点:可传递、可运算一切皆数据内存中所有操作的目标:数据操作包括:算术运算、逻辑运算、赋值、运行函数(调用函数传参)。2、内存内存条通电后产生的可存储数据的空间(临时的)内存产生和死亡:内存条(电路板)——> ......
  • 值得收藏,2024最新Java学习线路图
    目录概述01.Java基础02.JavaWeb03.Java开发框架04.中间件&服务框架05.面试题精选06.项目实战原文:https://mp.weixin.qq.com/s/2KATrfgSOiMtg2IIcnI8Jg概述作为一个称职的Java程序员,谁能拒绝拥有一张学习线路图呢,有了学习线路图,让学习事半功倍。废话不多说,直接......
  • Java中的异步日志记录:Logback与AsyncAppender的配置与优化
    Java中的异步日志记录:Logback与AsyncAppender的配置与优化大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java应用中,日志记录是关键的功能,但同步日志记录可能会影响性能。为了解决这个问题,异步日志记录可以显著提高应用的响应速度。本文将详细介绍......
  • 【开源免费】基于SpringBoot+Vue.JS房屋租赁系统(JAVA毕业设计)
    本文项目编号T020,文末自助获取源码\color{red}{T020,文末自助获取源码}......
  • JAVA开源项目 学生心理咨询评估系统 计算机毕业设计
    本文项目编号T017,文末自助获取源码\color{red}{T017,文末自助获取源码}......
  • 在Java服务端实现策略模式:如何灵活应对业务逻辑的多变性
    在Java服务端实现策略模式:如何灵活应对业务逻辑的多变性大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java服务端开发中,业务逻辑的复杂性和多变性常常需要灵活的设计模式来应对。策略模式是一种经典的设计模式,用于定义一系列算法,将每一个算法封装......
  • Java中的定时任务优化:从Cron表达式到高精度调度的实现
    Java中的定时任务优化:从Cron表达式到高精度调度的实现大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java应用开发中,定时任务是一种常见需求,尤其在后台服务中,定时执行任务是实现业务逻辑的关键部分。本文将探讨Java中的定时任务优化,从使用Cron表达......