【JUC】二十七、synchronized锁升级之无锁

2023-12-13 21:28

本文主要是介绍【JUC】二十七、synchronized锁升级之无锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1、背景
  • 2、Monitor、Java对象、线程如何关联起来的?
  • 3、synchronized锁升级
  • 4、锁升级之无锁

关于synchronized同步,能用无锁结构就不要用锁;能锁块,就不要锁整个方法;能用对象锁,就不要用类锁。

在这里插入图片描述
用锁能够保证数据的安全性,但性能下降。无锁,性能提升,但安全性下降,如何平衡?

1、背景

在Java早期版本,synchronized是重量级锁,效率低下,因为监视器锁monitor依赖底层操作系统的Mutex Lock(系统互斥量)来实现。

Java5之前,用户态和内核态之间的切换:
在这里插入图片描述

用户态和内核态之间切换指的是:

Java的线程是映射到操作系统的原生线程之上的(Java的start方法底层是native start0方法),因此阻塞和唤醒一个线程都需要操作系统介入去切换CPU的状态来完成(内核态),这种状态切换需要耗费处理器的时间,如果同步代码块很简单,那切换的时间可能比代码执行时间还长。

而用户态和内核态有各自专用的内存空间、专用的寄存器 ⇒ 因此,用户态切换到内核态还需要传递很多变量和参数过去,且内核也要去维护这些值。

鉴于以上,Java6后,引入轻量级锁和偏向锁,别一下就捅到重量级锁。一句话,为了尽量减少用户态和内核态的切换次数。

2、Monitor、Java对象、线程如何关联起来的?

如果一个Java对象被某线程锁住,则:

  • 该Java对象的Mark Word中的Lock word指向monitor的起始地址
  • Monitor的__Owner字段会存放拥有这个对象锁的线程的 id

在这里插入图片描述
在这里插入图片描述

关于Monitor的复习:【Monitor】

Monitor是在JVM底层实现的,底层代码是c++。本质是依赖于底层操作系统的Mutex Lock实现,而Mutex Lock 的切换需要从用户态转换到内核态中,因此状态转换需要耗费很多的处理器时间,所以synchronized在Java中是一个重量级操作。

3、synchronized锁升级

synchronized锁升级主要依赖Mark Word中锁标志位和释放偏向锁标志位。

在这里插入图片描述

  • 偏向锁:MarkWord存储的是偏向的线程ID

  • 轻量锁:MarkWord存储的是指向线程栈中Lock Record的指针

  • 重量锁:MarkWord存储的是指向堆中的monitor对象的指针

4、锁升级之无锁

无锁:即初始状态,一个对象被实例化后,如果还没有被任何线程竞争锁,那它就是无锁状态(001)

在这里插入图片描述
用JOL展示下,一个对象在无锁状态下,其对象头是如何记录的。

Object object = new Object();
//hashcode方法是native的,调用了才会生成,否则为0
System.out.println("10进制:" + object.hashCode());
System.out.println("16进制:" + Integer.toHexString(object.hashCode()));
System.out.println("2进制:" + Integer.toBinaryString(object.hashCode()));
System.out.println(ClassLayout.parseInstance(object).toPrintable());

结果分析:前25位是没使用的unUsed,再往后31位是hashcode,倒着看

在这里插入图片描述

这篇关于【JUC】二十七、synchronized锁升级之无锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/490016

相关文章

macOS升级后SVN升级

问题 svn: error: The subversion command line tools are no longer provided by Xcode. 解决 sudo chown -R $(whoami) /usr/local/Cellar brew install svn

关键字synchronized、volatile的比较

关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰于变量,而synchronized可以修饰方法,以及代码块。随着JDK新版本的发布,synchronized关键字的执行效率上得到很大提升,在开发中使用synchronized关键字的比率还是比较大的。多线程访问volatile不会发生阻塞,而synchronize

Golang支持平滑升级的HTTP服务

前段时间用Golang在做一个HTTP的接口,因编译型语言的特性,修改了代码需要重新编译可执行文件,关闭正在运行的老程序,并启动新程序。对于访问量较大的面向用户的产品,关闭、重启的过程中势必会出现无法访问的情况,从而影响用户体验。 使用Golang的系统包开发HTTP服务,是无法支持平滑升级(优雅重启)的,本文将探讨如何解决该问题。 一、平滑升级(优雅重启)的一般思路 一般情况下,要实现平滑

JeecgBoot 升级springboot版本到2.6.0

1. 环境描述 Jeecgboot 3.0,他所依赖的springboot版本为2.3.5Release,将springboot版本升级为2.6.0。过程全纪录,从2开始描述。 2. 修改springboot版本号 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-pare

欧拉系统 kernel 升级、降级

系统版本  cat  /etc/os-release  NAME="openEuler"VERSION="22.03 (LTS-SP1)"ID="openEuler"VERSION_ID="22.03"PRETTY_NAME="openEuler 22.03 (LTS-SP1)"ANSI_COLOR="0;31" 系统初始 kernel 版本 5.10.0-136.12.0.

Zookeeper集群是如何升级到新版本的

方案1:复用老数据方案 这是经过实践的升级方案,该方案是复用旧版本的数据,zk集群拓扑,配置文件都不变,只是启动的程序为最新的版本。 参考文章: Zookeeper集群是如何升级到新版本的 方案2:重新建立数据方案 该方案的思路是:先停掉一台follower的机器上的服务,然后加入一个新版本的zk(zk的数据目录是空的),然后启动新zk,之后新zk会把旧集群中的数据同步过来。之后再操作另

mysql数据库8.0小版本原地升级

mysql数据库8.0小版本原地升级 准备工作升级工作停库使用新版本软件启动数据库更新环境变量重启数据库 升级日志 OS release: CentOS 7.9升级前DB version: MySQL 8.0.30数据库升级安装包:mysql-8.0.36-linux-glibc2.12-x86_64.tar.xzMySQL Shell安装包:mysql-shell-8.0.36

【编程底层思考】详解Java的JUC多线程并发编程底层组件AQS的作用及原理

Java中的AbstractQueuedSynchronizer(简称AQS)是位于java.util.concurrent.locks包中的一个核心组件,用于构建锁和其他同步器。AQS为实现依赖于FIFO(先进先出)等待队列的阻塞锁和相关同步器提供了一套高效、可扩展的框架。 一、AQS的作用 统一同步状态管理:AQS提供了一个int类型的成员变量state,用于表示同步状态。子类可以根据自己

面试官:synchronized的锁升级过程是怎样的?

大家好,我是大明哥,一个专注「死磕 Java」系列创作的硬核程序员。 回答 在 JDK 1.6之前,synchronized 是一个重量级、效率比较低下的锁,但是在JDK 1.6后,JVM 为了提高锁的获取与释放效,,对 synchronized 进行了优化,引入了偏向锁和轻量级锁,至此,锁的状态有四种,级别由低到高依次为:无锁、偏向锁、轻量级锁、重量级锁。 锁升级就是无锁 —>

【Java编程的思想】理解synchronized

用法和基本原理 synchronized可以用于修饰类的实例方法、静态方法和代码块 实例方法 在介绍并发基础知识的时候,有一部分是关于竞态条件的,当多个线程访问和操作同一个对象时,由于语句不是原子操作,所以得到了不正确的结果。这个地方就可以用synchronized进行处理 public class Counter {private int count;public synchroni