前言

今天碰到一个synchronized锁升级的问题, 查了查, 发现一个帖子举例说明比较贴切, 特此转发, 如有问题, 欢迎讨论说明

转自: 木叶盒子 https://www.bilibili.com/read/cv15920091/

java提供两种锁:lock和synchronized,关于二者的区别,网上一个说法非常好:

synchronized相当于自动挡汽车,使用简单,可以覆盖大部分使用场景
但如果你想玩漂移等特殊操作,就需要lock,使用相对麻烦,但可以实现一些特殊场景,如公平锁

实际上二者出身就有本质区别,synchronized是官方的,而lock是民间的李二狗写出来的,起初刚开始lock无论在功能上还是性能上都超越了synchronized,可以说狠狠的打了官方的脸。

因此在1.5版本之后官方通过锁升级对synchronized的性能做了提升,本文主要简单介绍synchronized锁升级的过程

synchronized

ynchronized是一种对象锁(锁的是对象而非引用),作用粒度是对象,java中每个对象都可以上锁(同一时间只有一个线程能上锁成功),而且通过对象内部存储的markword标记锁状态。

synchronized加锁方式

  • 同步实例方法,锁是当前实例对象
  • 同步类方法,锁是当前类对象
  • 同步代码块,锁是括号里面的对象
public class Syc {
   Object lock = new Object();
   public synchronized static void go() {
// 锁的是Syc.class对象
   }
   public synchronized void say() {
// 锁的是Syc对象实例
}
  synchronized (lock) {
// 锁的是lock对象实例        
}    
}

锁升级

首先过一下synchronized锁升级的过程

1.偏向锁

当只有一个线程获得了锁,锁就进入偏向模式,MarkWord标识偏向状态,当这个线程再次请求锁时,无需再做任何同步操作,即获取锁的过程,这样就省去了大量有关锁申请的操作。

2.轻量级锁

当有其它线程要获取锁,竞争不是很激烈,锁进入轻量级锁,MarkWord标识轻量级状态,此时等待锁的线程开始自旋,即空循环等待锁释放,此过程不释放cpu。

3.重量级锁

当获取锁的竞争变的激烈,比如来了很多个线程或者某个线程自旋等待的次数太多了,锁进入重量级锁,MarkWord标识重量级状态,重量级锁依赖操作系统的Mutex lock实现,此时等待锁的线程挂起,当锁释放后再由操作系统唤醒重新尝试获取锁,由于借助操作系统,导致用户态内核态切换,此过程时间成本比较高。

原始的synchronized是直接使用重量级锁,才会导致性能很低,加入锁升级才使得synchronized性能获得很大提升。

理解

以上讲解了synchronized锁升级的过程,如果不好理解,还是拿现实生活举个例子:

假设某公司有多个会议室,每个团队需要获取到会议室的锁才能进去开会,会议室门口挂着一个写字板,时刻记录当前会议室使用状态。

  • 会议室相当于对象
  • 团队相当于线程
  • 会议室的锁相当于对象的锁
  • 写字板相当于MarkWord

1.偏向锁

公司发现大部分时间,同一个会议室都是同一个团队占用,于是当A团队第一次占用会议室时,在写字板上写上偏向 A团队,下次A团队进入不用修改就可以直接进入会议室,大大提升了开会效率。

如果B团队想使用会议室,此时A团队已经不使用该会议室,则修改写字板偏向 B团队。

这就是偏向锁,经过研究发现,在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,因此为了减少同一线程获取锁带来的开销,所以引入偏向锁。

2.轻量级锁

如果B团队想使用会议室,此时A还占用着会议室(写字板上记录偏向 A团队),此时出现了竞争,写字板上修改为轻量竞争,B团队哪也不去,就在会议室外原地打转(自旋)等着,因为公司大部分会议时间都很短,B相信A一般会很快出来。

如果A确实一会就出来了,B马上去抢会议室的锁。

这就是轻量级锁,偏向锁出现了竞争会升级为轻量级锁,因为大部分线程占用锁的时间不会特别长,所以等待线程刚开始不需要挂起,只需要通过空转自旋等待,一般很快就会获取到锁,比过程一直占用着cpu。

3.重量级锁

上面的情况,如果B等了很久A都不出来,或者这段时间公司特别繁忙,各团队频繁开会,还有C,D,E...等等团队也要使用该会议室,这时如果A在里面开会没完没了,其它团队一直在外面傻转着也不是事。

这时候就要请会议室管理员帮忙了,他让各团队都回去睡觉吧,写字板上修改为重量竞争,等A团队开完会出来,我负责通知其它团队,你们再过来抢会议室的锁。

这样在会议室竞争特别激烈时,请会议室管理员帮忙有效的避免了等待团队傻等,但如果在竞争不激烈的情况下就没有必要请出会议室管理员,毕竟造成额外开销,而且靠会议室管理员通知再来抢会议室肯定比站会议室外面等要慢很多。

这就是重量级锁,其中会议室管理员相当于操作系统,当某个线程自旋次数过多或者多个线程同时竞争锁,锁竞争变的激烈,轻量级锁升级为重量级锁,此时等待线程都挂起,对象锁释放后再由操作系统唤醒线程,此过程开销很大。

synchronized最开始就是不管竞争激不激烈都使用重量级锁导致性能很低,但竞争激励时如果任由等待线程空转消耗跟大,所以竞争激励升级为重量级锁也是非常合理。

其他

再补充几个问题

可重入锁

synchronized是一种可重入锁,比如有两个方法A,B锁的都是同一个对象,其中A调用B,那么某线程获取锁后进入A方法也能顺利进入B方法,即自己不会锁自己(否则synchronized修饰的方法都不能递归了),常用的ReentrantLock也是可重入锁。

公平/非公平

从上面的描述也会发现,当某个线程释放锁,其它线程会重新竞争锁,没有先来后到,就跟抢公交一样一拥而上,这就是不公平,我们的 synchronized就是一个非公平锁。

如果想实现公平锁,可以用ReentrantLock,他会维护一个队列,先到先得,就像排队上地铁,文明多了。

简单的理解synchronized锁升级的更多相关文章

  1. 再谈synchronized锁升级

    在图文详解Java对象内存布局这篇文章中,在研究对象头时我们了解了synchronized锁升级的过程,由于篇幅有限,对锁升级的过程介绍的比较简略,本文在上一篇的基础上,来详细研究一下锁升级的过程以及 ...

  2. Synchronized锁升级原理与过程深入剖析

    Synchronized锁升级原理与过程深入剖析 前言 在上篇文章深入学习Synchronized各种使用方法当中我们仔细介绍了在各种情况下该如何使用synchronized关键字.因为在我们写的程序 ...

  3. Synchronized锁升级

    Synchronized锁升级 锁的4中状态:无锁状态.偏向锁状态.轻量级锁状态.重量级锁状态(级别从低到高) 为什么要引入偏向锁? 因为经过HotSpot的作者大量的研究发现,大多数时候是不存在锁竞 ...

  4. 详细了解 synchronized 锁升级过程

    前言 首先,synchronized 是什么?我们需要明确的给个定义--同步锁,没错,它就是把锁. 可以用来干嘛?锁,当然当然是用于线程间的同步,以及保护临界区内的资源.我们知道,锁是个非常笼统的概念 ...

  5. 深入并发锁,解析Synchronized锁升级

    这篇文章分为六个部分,不同特性的锁分类,并发锁的不同设计,Synchronized中的锁升级,ReentrantLock和ReadWriteLock的应用,帮助你梳理 Java 并发锁及相关的操作. ...

  6. synchronized锁升级详细过程

    java对象头由3部分组成: 1.Mark Word 2.指向类对象(对象的class对象)的指针 3.数组长度(数组类型才有) 重点是 Mark Word结构,下面以32位HotSpot为例: 一. ...

  7. 并发编程:synchronized 锁升级过程的验证

        关于synchronized关键字以及偏向锁.轻量级锁.重量级锁的介绍广大网友已经给出了太多文章和例子,这里就不再重复了,也可点击链接来回顾一下.在这里来实战操作一把,验证JVM是怎么一步一步 ...

  8. 【大厂面试07期】说一说你对synchronized锁的理解?

    synchronized锁的原理也是大厂面试中经常会涉及的问题,本文主要通过对以下问题进行分析讲解,来帮助大家理解synchronized锁的原理. 1.synchronized锁是什么?锁的对象是什 ...

  9. synchronized锁及其锁升级

    点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. 多线程加锁有两种方式 利用Sychronized关键字 利用Lock接口 ...

  10. Synchronized锁及其膨胀

    一.序言 在并发编程中,synchronized锁因其使用简单,在线程间同步被广泛应用.下面对其原理及锁升级过程进行探究. 二.如何使用 1.修饰实例方法 当实例方法被synchronized修饰时, ...

随机推荐

  1. [OC] Block 是什么

    Block 是 带有自动变量的匿名函数.  emmmm 反正我看了也不懂,我们一点点用具体的例子分析一下block. 1. 我们现在要在一个文件中使用block(我们后面再提到两个界面传值的block ...

  2. Kubernetes--Pod存活性探测(设置exec探针)

    有不少应用程序长时间持续运行后会逐渐转为不可用状态,并且仅能通过重启操作恢复,Kubernetes的容器存货性探测机制可发现诸如此类的问题,并根据探测结果结合重启策略触发后续的行为.存活性探测是隶属于 ...

  3. 「SOL」JOISC2021 解题报告

    JOIS(egment-Tree)C 1. 前言 很早之前教练让我们做这套题,我以为这套题应该挺简单,用几天的空余时间就能刷完,结果预想的短周期刷题变成了长周期刷题--(好像是整个团队里最后一个刷完的 ...

  4. Django安装与启动

    安装 python -m pip install Django  查看版本 python -m django --version打开命令行,cd 到一个你想放置你代码的目录,然后运行以下命令: dja ...

  5. Java基础学习:5、递归

    1.递归:就是方法自己调用自己. public class Test01 { public void test(int n) { if (n > 2) { test(n -1); } Syste ...

  6. 图像高斯滤波的Verilog实现

    高斯滤波的原理: 高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程.通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过 ...

  7. 攻防世界-fileclude

    攻防世界的一道文件包含题目 include("文件名"):会将文件中的内容视为代码块接入include所在代码中,输出的只是执行后的结果,文件中的注释.定义等无法查看. 本题中可以 ...

  8. drupal clean url 配置

    使用 find / -name "apachectl"查找文件目录下执行 ./apachectl -v 转载于:https://www.cnblogs.com/thinkingth ...

  9. docker tomcat 环境构建

    docker build -t repos_local/centos-jdk7-tomcat7:0.0.1 . -t 设置tag名称, 命名规则registry/image:tag . 表示使用当前目 ...

  10. (K8s学习笔记五)Pod的使用详解

    1.Pod用法 K8s里使用的容器不能使用启动命令是后台执行程序,如:nohup ./start.sh &,该脚本运行完成后kubelet会认为该Pod执行结束,将立刻销毁该Pod,如果该Po ...