Java中锁的深入理解

目录

对象头的理解

Monitor(锁)

锁类型

偏向锁

偏向锁的优化机制

轻量级锁

重量级锁


对象头的理解

在32位Java虚拟机中普通对象的对象头是占用8个字节,其中4个字节为Mark Word。用来存储对象的哈希值,对象创建后在JVM中的生命(经历GC回收后存活次数)等信息。另外四个字节为Klass Word用来存储对象类型,是String还是Student又或是Teacher。

Mark Word的存储结构为

Monitor(锁)

Monitor锁结构如下

这三个区域分别代表

  1. WaitSet:线程通过wait()方法进入的阻塞状态,从Owner进入WaitSet集合,通过notify()方法唤醒后进入EntryList。
  2. EntryList:阻塞线程集合,需要通过非公平竞争去获取锁
  3. Owner:存储当前获取锁的线程。

当一个对象被加入重量级锁时,Mark Word会存储Monitor的地址。

锁类型

均针对于synchronized来进行辨析

偏向锁

偏向锁CPU损耗是最小的一种,在这种锁状态下,系统会认为这个锁通常只会由一个线程独占。默认情况下是开启的,对于本就是需要多线程争抢的对象来说,可以选择禁用偏向锁。

轻量级锁每次都会进行CAS操作,这也会消耗CPU资源,因此,偏向锁采用的是对象中的Mark Word存储的是线程ID。每次加锁时,先判断对象中的Mark Word是否是本线程ID(轻量级锁和偏向锁的锁对象Mark Word存储的信息不同,轻量级锁存储的是对象的hash值,偏向锁存储的是ThreadID)。

当对象被加入偏向锁后,记录的ThreadID并不会因为解锁而消失,而是继续存储在对象的Mark Word中。如果其他线程获取该对象加锁,会撤销ThreadID,变成轻量级锁

当一个可偏向对象调用hashCode方法后,会关闭偏向锁,用来对象的Mark Word用来存储该对象的hash值。

偏向锁的优化机制

批量重偏向:当可偏向对象因为被多个线程访问导致的撤销偏向锁次数过多时(默认值为20),后续的可偏向对象就不会再次进行撤销偏向锁了,因为撤销偏向锁也是需要CPU资源的。而是进行重偏向,JVM会认为初始偏向时,偏向错了,将后续的可偏向对象中的Mark Word修改为现在正在执行的ThreadID,已经被撤销偏向锁的对象则无法恢复。

批量撤销:当偏向锁被撤销次数过多时(默认为40次),JVM会认为,就不应该开启偏向锁,此后创建的每一个对象都是不可偏向的。

轻量级锁

在这种锁状态下,通常应用是一个对象虽然会被多个线程访问,但是多个线程的访问是错开时间的,并不存在竞争关系。

static final Object obj = new Object(); 
public static void method1(){synchronized(obj){method2();}
}public static void method2(){synchronized(obj){}
}

首先这是一个线程执行,那么在执行method1时,栈帧中会创建一个Lock Record(锁记录)。里面存储对象的引用地址以及存储锁对象的Mark Word。

如下图所示

接着进行下一步,Object reference指向锁对象,并尝试通过cas交换锁对象的Mark Word。

如下图所示

如果cas成功,那么对象的对象头Mark Word存储的是锁记录的地址以及其状态,表示对该对象进行加锁

如果cas失败,则要分情况看待:

  • 一种是,该对象已经被其他线程上锁,这时说明该对象存在竞争情况,进入锁膨胀状态
  • 一种是,该对象已经被该线程上锁,这属于锁重入,再加入一条Lock Record作为重入计数。

对于第二种情况进行分析。在进行method1时,又进行了method2,此时,会cas失败。但是并不影响。

进行解锁时,取出的锁记录为null时,说明存在重入,此时重入计数-1。

如果取出的锁记录不为null,说明该线程已经不对该对象上锁了,进行真正的解锁操作,通过cas将对象的原有Mark Word恢复给该对象。如果成功的话说明解锁成功,如果cas失败说明进行了锁膨胀升级到了重量级锁,此时去执行重量级锁解锁流程。

重量级锁

最耗费CPU资源的加锁方式。

当线程0已经为对象加上了轻量级锁后,线程1再次对该对象加入轻量级锁,此时CAS失败,那么线程1会为该对象申请Monitor锁。然后自己进入Monitor锁中的EntryList

申请Monitor锁后,会将其地址存储在该对象的Mark Word中。

当线程0进行解锁操作时,会发现CAS解锁失败,此时会进入重量级解锁流程,即通过Monitor地址,找到Monitor锁后,将Owner设置为null,唤醒EntryList中的阻塞线程。


自旋优化:当线程加锁时发现锁被占用会进入阻塞状态,但是这样会大量进行线程上下文切换,比较占用CPU,因此可以使用自旋优化,所谓自旋优化,是线程循环获取锁,失败后还是要去获取锁,如果在规定次数内还没有获取到锁,那么进入阻塞状态,因为这是一个循环过程,也是要占用CPU资源的。注意:单核CPU没有自旋的必要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/195470.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 运算符重载详解

本篇内容来源于对c课堂上学习内容的记录 通过定义函数实现任意数据类型的运算 假设我们定义了一个复数类&#xff0c;想要实现两个复数的相加肯定不能直接使用“”运算符&#xff0c;我们可以通过自定义一个函数来实现这个功能&#xff1a; #include <iostream> using…

解决WPF项目xaml出现“正在等待IntelliSense完成”的问题

在WPF项目xaml里经常出现“正在等待IntelliSense完成”的场景&#xff0c;如下图&#xff1a; 解决办法 工具–选项

Asp.net MVC Api项目搭建

整个解决方案按照分层思想来划分不同功能模块&#xff0c;以提供User服务的Api为需求&#xff0c;各个层次的具体实现如下所示&#xff1a; 1、新建数据库User表 数据库使用SQLExpress版本&#xff0c;表的定义如下所示&#xff1a; CREATE TABLE [dbo].[User] ([Id] …

系列三、GC垃圾回收算法和垃圾收集器的关系?分别是什么请你谈谈

一、关系 GC算法&#xff08;引用计数法、复制算法、标记清除算法、标记整理算法&#xff09;是方法论&#xff0c;垃圾收集器是算法的落地实现。 二、4种主要垃圾收集器 4.1、串行垃圾收集器&#xff08;Serial&#xff09; 它为单线程环境设计&#xff0c;并且只使用一个线程…

机器学习赋予用户“超人”的能力来打开和控制虚拟现实中的工具

原创 | 文 BFT机器人 最近&#xff0c;剑桥的研究人员开发了一种虚拟现实应用程序&#xff0c;只需用户手部的移动即可打开和控制一系列3D建模工具。 来自剑桥大学的研究人员利用机器学习开发了“HotGestures”类似于许多桌面应用程序中使用的热键&#xff08;快捷键&#xff…

【C++】一文全解C++中的异常:标准库异常体系&自定义异常体系(含代码演示)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.C语言传统的处理错误的方式二.C异常…

MVSNet论文笔记

MVSNet论文笔记 摘要1 引言2 相关基础2.1 多视图立体视觉重建&#xff08;MVS Reconstruction&#xff09;2.2 基于学习的立体视觉&#xff08;Learned Stereo&#xff09;2.3 基于学习的多视图的立体视觉&#xff08;Learned MVS&#xff09; Yao, Y., Luo, Z., Li, S., Fang,…

2024年csdn最新最全面的fiddler教程【1】

Fiddler简介 Fiddler是比较好用的web代理调试工具之一&#xff0c;它能记录并检查所有客户端与服务端的HTTP/HTTPS请求&#xff0c;能够设置断点&#xff0c;篡改及伪造Request/Response的数据&#xff0c;修改hosts&#xff0c;限制网速&#xff0c;http请求性能统计&#xff…

三极管-开关电路-电路电子-嵌入式开发-物联网开发-电子元件

一、概述 本文我们主要讲解电子电路中十分重要的元件--三极管。三极管常常被用来当作开关或作为放大电流的作用&#xff0c;下面我们将主要围绕着其作为开关电路的使用来介绍三极管。 二、分类 学习三极管前&#xff0c;我们必须认识三极管的三级&#xff0c;包含箭头的一端为发…

第93步 深度学习图像分割:PSPNet建模

基于WIN10的64位系统演示 一、写在前面 本期&#xff0c;我们继续学习深度学习图像分割系列的另一个模型&#xff0c;PSPNet。 二、PSPNet简介 &#xff08;1&#xff09;金字塔池化模块 (Pyramid Pooling Module) PSPNet的核心是其金字塔池化模块&#xff0c;该模块能够捕…

【Python仿真】基于EKF的传感器融合定位

基于EKF的传感器融合定位&#xff08;Python仿真&#xff09; 简述1. 背景介绍1.1. EKF扩展卡尔曼滤波1.1.1.概念1.1.2. 扩展卡尔曼滤波的主要步骤如下&#xff1a;1.1.3. 优、缺点 1.2. 航位推算1.3. 目前航位算法的使用通常与卡尔曼滤波相结合使用2. 分段代码 2.1. 导入需要的…

ERR:Navicat连接Sql Server报错

错误信息&#xff1a;报错&#xff1a;未发现数据源名称并且未指定默认驱动程序。 原因&#xff1a;Navicat没有安装Sqlserver驱动。 解决方案&#xff1a;在Navicat安装目录下找到sqlncli_x64.msi安装即可。 一键安装即可。 Navicat链接SQL Server配置 - MarchXD - 博客园 …