首页 > 编程语言 >Java并发编程 - 基础(悲观锁与synchronized)(偏向锁、轻量级锁、锁优化)

Java并发编程 - 基础(悲观锁与synchronized)(偏向锁、轻量级锁、锁优化)

时间:2024-08-21 09:23:30浏览次数:13  
标签:Java synchronized 线程 轻量级 悲观 偏向

Java 并发编程中的悲观锁和 synchronized 关键字,以及 Java 内存模型中的锁优化机制(如偏向锁、轻量级锁)都是非常重要的概念。下面将详细介绍这些内容。

悲观锁(Pessimistic Locking)

悲观锁假设数据会发生冲突,因此在读取数据时就加锁,以防止其他线程修改数据。这种方式虽然能保证数据的一致性,但可能会降低系统的并发性能,因为它增加了锁的持有时间。

悲观锁的实现方式:
  1. 数据库中的悲观锁:在数据库中,可以使用行级锁或者表级锁来实现悲观锁。
  2. Java 中的悲观锁:在 Java 中,最常用的悲观锁实现方式是使用 synchronized 关键字或者 ReentrantLock 类。

synchronized 关键字

synchronized 是 Java 中内置的关键字之一,它可以用来实现悲观锁。当一个线程进入一个 synchronized 代码块或者方法时,它会获取一个锁,其他试图获取相同锁的线程会被阻塞,直到第一个线程释放锁。

示例
public class SynchronizedExample {
    private int counter = 0;

    public synchronized void increment() {
        counter++;
    }

    public synchronized int getCount() {
        return counter;
    }
}

在这个例子中,incrementgetCount 方法都使用了 synchronized 关键字来保证线程安全。

Java 内存模型中的锁优化

Java 内存模型针对 synchronized 关键字进行了多种优化,以提高程序的并发性能。这些优化包括偏向锁、轻量级锁等。

偏向锁(Biased Locking)

偏向锁是 Java 5 引入的一种锁优化策略,它的目标是在无多线程竞争的前提下尽量减少不必要的轻量级锁执行路径。当一个线程访问同步块并获取锁时,会在对象头中存储当前线程的 ID,以后该线程再次进入时可以直接进入代码块,而无需再次获取锁。

轻量级锁(Lightweight Locking)

轻量级锁是 Java 6 引入的一种锁优化策略,它使用 CAS(Compare-and-Swap)操作来实现。当一个线程尝试获取锁时,首先尝试使用 CAS 将对象头中的锁标志位设置为 01(表示轻量级锁),如果 CAS 成功,则表示当前没有其他线程竞争锁,直接获取锁;如果 CAS 失败,则需要膨胀为重量级锁。

锁膨胀

当轻量级锁尝试获取锁失败时,会升级为重量级锁。重量级锁使用操作系统提供的互斥锁(mutex)来实现,这会导致线程挂起和唤醒,从而增加上下文切换的开销。

锁的优化过程

以下是 synchronized 锁的优化过程:

  1. 无锁状态:初始状态下,对象头中没有锁标志位,表示无锁。
  2. 偏向锁:当第一个线程获取锁时,如果对象头中没有锁标志位,就会尝试使用 CAS 设置锁标志位为 01(偏向锁),并把线程 ID 存储在对象头中。如果 CAS 成功,则进入偏向锁状态。
  3. 轻量级锁:如果对象已经是偏向锁状态,且当前线程与对象头中的线程 ID 相同,则直接进入同步块;如果不同,则尝试获取轻量级锁。
  4. 重量级锁:如果轻量级锁获取失败,则锁膨胀为重量级锁,此时线程会阻塞,等待锁的释放。

总结

Java 中的锁优化机制通过使用偏向锁和轻量级锁等技术来减少锁的竞争和开销,从而提高并发性能。synchronized 关键字提供了一种简单而强大的方式来实现悲观锁,而 Java 内存模型则负责自动选择最合适的锁优化策略。理解这些机制有助于开发者编写高效、可靠的并发程序。

标签:Java,synchronized,线程,轻量级,悲观,偏向
From: https://blog.csdn.net/qq_33240556/article/details/141316387

相关文章

  • Java中的分布式缓存解决方案:Redis与Ehcache
    在现代企业级应用中,性能和高可用性是两个重要的考量因素。分布式缓存作为解决性能瓶颈的有效手段,能有效减轻数据库的压力并提高系统的响应速度。本文将深入探讨Java中两种常用的分布式缓存解决方案:Redis与Ehcache,并通过代码示例演示它们在实际应用中的使用。分布式缓存的基本......
  • Java Lambda 使用备忘
    publicBooleanerpUnAudit(WorkOrderErpUnAuditDtoworkOrderErpUnAuditDto){List<WorkOrderErpUnAuditDto.ModelDTO>listWorkOrderErpUnAuditDto=workOrderErpUnAuditDto.getModel();List<String>billNos=listWorkOrderErpUnAudit......
  • Docker无法运行java虚拟机报错There is insufficient memory for the Java Runtime
    镜像导入到docker后无法启动容器的问题,但是上传到别的服务器上面又可以正常启动容器,报错信息如下:#ThereisinsufficientmemoryfortheJavaRuntimeEnvironmenttocontinue.#CannotcreateGCthread.Outofsystemresources.#Cannotsavelogfile,dumptoscree......
  • 浅谈Java Spring Boot
    一、基本介绍SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,SpringBoot致力于在蓬勃发展的快速应用开发领域(rapidapplicatio......
  • 浅谈 Java Spring框架
    一、基本介绍Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。二、核心特性依......
  • Java面试题--JVM大厂篇之未来已来:为什么ZGC是大规模Java应用的终极武器?
           ......
  • java项目部署到linux
    手工部署打包获取打包的jar包将jar包放到linux中(可通过xftp软件)的usr/local/ruiji执行jar包java-jarjar包名称指定端口:java-jarjar包名称--server.port=端口号如果端口被占用,查看端口号命令netstat-tuln|grep:8080根据端口号杀死进程lsof-i:8......
  • java: 错误: 无效的源发行版:17
    错误信息java:错误:无效的源发行版:17原因这个错误通常表示你的Java编译器版本不支持你指定的Java版本。解决方式pom.xml版本改为18或8<properties><java.version>18</java.version></properties>设置:改完直接finish键盘输入1.8,按自己......
  • BT5 2011.4.社会工程学.1.JAVA
    4.社会工程学工具 内容简介第一部分:JavaAppletAttackMethod第二部分:CredentialHarvesterAttackMethod 第一部分JavaAppletAttackMethod 拓扑介绍 SET介绍TheSETisanadvanced,multi-function,andeasytousecomputerassistedsocialengineering......
  • Java微信授权登录小程序接口
    1.微信授权登录小程序的流程是什么微信授权登录小程序的流程是一个涉及前端和后端交互的过程,主要目的是让用户能够使用微信账号快速登录小程序,避免重复输入用户名和密码。以下是该流程的详细步骤:1.1前端操作(1)触发登录:用户在小程序中点击“登录”按钮或进入需要登录的页面时,系......