synchronized锁及其锁升级

点赞再看,养成习惯,微信搜索「 小大白日志」关注这个搬砖人。

文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。

多线程加锁有两种方式

  • 利用Sychronized关键字
  • 利用Lock接口子类ReentrantLock类
Sychronized关键字与Lock接口比较
  • sychronized是java内置的关键字,查看不到线程是否获取到了锁;Lock接口是一个java接口,可以查看是否获取到了锁
  • synchronized可以加在方法、代码块上;Lock接口写在代码里;
  • synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
  • synchronized加在方法、代码块上,同一时刻只能有一个线程使用这段代码,其他线程必须等待,并且其他线程不能响应中断(响应中断=中断等待的状态:将线程从等待状态变为就绪状态,以便线程能继续往下执行代码;线程响应中断后会抛出一个异常,业务代码必须手动处理该异常);而Lock接口可以响应中断
  • Lock接口必须手动调用unlock()释放锁,否则容易造成死锁想象,一般在finally中调用unlock();

synchronized放弃锁只有两种情况:

(1)线程执行完了同步代码块的内容

(2)发生异常;而lock不同,它可以设定超时时间,也就是说他可以在获取锁时便设定超时时间,如果在你设定的时间内它还没有获取到锁,那么它会放弃获取锁然后响应中断操作。
* lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

synchronized锁升级

基础知识

每个【锁=锁对象】的对象头由两部分组成:Classpointer+Markword

(1)Classpointer=对象类型指针,JVM就是通过它来确定当前对象是属于哪个class实例

(2)Markword,32位的jvm中Markword是占4B=4byte=32b=32位,存放对象运行时的数据(对象gc时的分代年龄,对象hashcode,当前锁为偏向锁时的线程ID),synchronized锁机制与32位中的最后3位(1+2)密切相关,最后2位是普通锁位,倒数第三位是偏向锁位:

synchronized锁及其锁升级
当锁对象被创建出来,此时锁对象为无锁状态,(偏向锁位,普通锁位)=(0,01),所有无锁对象都是可偏向的,即可以被任意线程加偏向锁,当第一个线程对该锁对象加锁时,会把偏向锁位由0变1代表偏向锁生效,同时把线程ID插入锁对象头的Markword中
synchronized锁升级的过程(无锁->…->重量级锁)

锁膨胀的过程:无锁(没有线程)->偏向锁(1个线程)->轻量级锁(有第二个及以上的线程竞争锁)->重量级锁(有三个及以上的线程竞争锁)

偏向锁

如何加锁:线程A第一次访问同步代码块中的代码时,先检查当前锁是否可偏向(偏向锁位为0),是则通过CAS获取锁,获取锁之后会在synchronized关键字对应的锁对象的对象头中,在Markword里记录本线程ID,线程A再次访问该同步代码块中的代码时,直接比较锁对象头的Markword的线程ID是否是本线程ID,若是则线程A可重入取锁进而直接访问同步代码块,否则说明是另外一个线程B想访问同步代码块,从而B竞争同一个【锁=锁对象】,此时锁升级

如何锁升级为轻量级锁:当线程B想访问synchronized同步代码块时,会检查synchronized关键字对应的锁对象的对象头中,Markword中线程ID是否为线程B的ID,若不是则B再检查锁对象头中记录的线程A是否还存活,不存活则直接把锁对象先置为无锁状态,再获取锁使其变为偏向锁;若存活则先暂停线程A,撤销偏向锁,再把【锁=锁对象】升级为轻量级锁,然后B线程自旋(不断循环调用cas获取锁,自旋会消耗cpu使得cpu空转,所以自旋有次数限制)

轻量级锁

如何升级为重量级锁:B线程在访问同步代码块时发现A线程正在占用锁对象,故把【锁=锁对象】升级为轻量级锁,然后B自旋了,这时又有C线程来,此时轻量级锁升级为重量级锁,同时除了得到锁的那个线程,其他线程均会被阻塞

synchronized由无锁状态膨胀为重量锁的特点
  • jvm默认延迟4s后才开启偏向锁,在这4s期间的(锁=锁对象)又叫匿名偏向锁,4s后才记录得到锁的线程,可通过【-XX:BiasedLockingStartUpDelay=0】取消延时,可通过【-XX:-UseBiasedLocking = false】设置不要偏向锁
  • 除了偏向锁可以降为无锁状态,其他锁只能升级,不能降级
  • 偏向锁和轻量级锁在用户态维护,而重量级锁在内核态维护

OK,如果文章哪里有错误或不足,欢迎各位留言。

创作不易,各位的「 三连」是二少创作的最大动力!我们下期见!

Original: https://www.cnblogs.com/mofes/p/15022373.html
Author: 明天喝可乐
Title: synchronized锁及其锁升级

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/589761/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • SpringBoot 项目中引入Swagger (Springfox)

    maven中引入springfox-boot-stater io.springfox springfox-boot-starter 3.0.0 编写配置文件 @Configurat…

    Java 2023年5月30日
    063
  • Spring事务源码解读

    一、Spring事务使用 1.通过maven方式引入jar包 com.alibaba druid 1.2.8 mysql mysql-connector-java 8.0.28 o…

    Java 2023年6月13日
    091
  • springboot集成webservice,基于用户名,密码

    springboot集成webservice,基于用户名,密码 https://blog.csdn.net/hsqingwei/article/details/89331959 p…

    Java 2023年5月30日
    085
  • Mall商城的高级篇的开发(一)全文检索和Nginx的反向代理

    Mall商城的高级篇的开发 项目的整体架构图 实现全文检索和日志分析 在本项目中,全文检索使用 ElasticSearch来做全文检索。 做日志存储和日志检索(日志的快速定位)使用…

    Java 2023年6月5日
    0102
  • Spring-Cloud-Commons模块

    本文介绍SpringCloud的另一个基础模块 Spring Cloud Commons模块 。只要在项目的pom文件中引入了 spring-cloud-starter 依赖包 ,…

    Java 2023年5月30日
    083
  • freemarker

    1.freemarker 介绍 FreeMarker 是一款 模板&a…

    Java 2023年6月9日
    0123
  • 基于XML的显式配置

    Spring提供了两种配置方式:一种是显式配置;一种是自动配置。显式配置又分为两种:一种是基于XML的显式配置;一种是基于Java的显式配置。自动配置只有一种,即基于注解的自动配置…

    Java 2023年6月5日
    095
  • Could not resolve placeholder ‘usp.server.port’ in value “${usp.server.port}”

    我是接触的新项目遇到的这个问题,代码肯定没啥问题(才拷过来的),网上找了很多才发现我这个是个微服务的项目,这个${usp.server.port}表示就去配置中心微服务得到值,搞了…

    Java 2023年6月6日
    050
  • Java避坑宝典《Java业务开发常见错误100例》上线了

    写这个专栏的缘起 之前我写过一篇博客:《朱晔的互联网架构实践心得S2E2:写业务代码最容易掉的10种坑》,引起的关注还是挺多的。后来和极客时间的编辑一拍即合决定以这个为题写一个专栏…

    Java 2023年5月29日
    091
  • 创建SpringCloud项目

    一、创建父工程 1、选择maven,直接–>next 2、填写项目相关的信息,next 3、填写项目名和项目位置–>finish 4、修改pom…

    Java 2023年5月30日
    0103
  • Node版本更新及切换

    Node版本升级 清除npm缓存 npm cache clean -f n&#x6A…

    Java 2023年6月8日
    088
  • [推荐]MyBatis 核心技术与面试 34 讲

    MyBatis 核心技术与面试 34 讲 职业生涯中常被问到: 如何成为某方面的高手? 如何快速搞定某项技术? 我现在的水平处于什么阶段? …… 我暗暗想,…

    Java 2023年5月30日
    0208
  • Maven配置私有仓库

    前言 当公司或个人具有自己独有的jar时,不想公开,一般就会放在自己的私有Maven仓库中,在项目中需要引用,此时就需要将公司私有仓库配置到maven当中,一般我们的maven配置…

    Java 2023年6月8日
    084
  • Git本地连接远程仓库

    初始化远程仓库(复制连接) 本地新建文件夹,以后你的代码就是丢在里面了. 右击鼠标,选择 Git bash git init //初始化仓库 touch 文件名.txt //新建一…

    Java 2023年6月5日
    076
  • Redis和Mysql保持数据一致性

    1、简述 在高并发的场景下,大量的请求直接访问Mysql很容易造成性能问题。所以,我们都会用Redis来做数据的缓存,削减对数据库的请求。但是,Mysql和Redis是两种不同的数…

    Java 2023年6月8日
    080
  • 顺序存储二叉树

    顺序存储二叉树的概念 从数据存储来看,数组存储方式和树的存储方式可以相互转换,即 数组可以转换成树, 树也可以转换成数组, 看下面的示意图。 要求: 右图的二叉树的结点,要求以数组…

    Java 2023年6月15日
    095
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球