前言

  • 物竞天择,适者生存。JDK也在不断的优化中。关于JDK中synchronized锁内部也是不断的优化,前面我们分析了偏向锁用来解决初期问题,随着争抢的不断堆积轻量级锁营运而生。
  • 关注我,一个不断进步的社畜码农,带你一起摆脱危机

轻量级锁

  • 上面说了没有竞争情况并且开启偏向锁的同时,才会产生偏向锁。但是偏向锁是不会主动撤销的。我们看下下面案列
  • vm配置如下-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
 public class SimpleTest {
     public static void main(String[] args) {
         SimpleTest test = new SimpleTest();
         System.out.println(ClassLayout.parseInstance(test).toPrintable());
         synchronized (test) {
             System.out.println("hello world");
             System.out.println(ClassLayout.parseInstance(test).toPrintable());
        }
         System.out.println("锁释放后:"+ClassLayout.parseInstance(test).toPrintable());
 ​
    }
 }
  • 我们能够看到上锁前,上锁中,上锁后三个过程test对象中的markword一直都是偏向锁。这说明不会主动撤销

  • 基于这个前提下,我们试想下有两个线程不同时间针对同一个对象上锁,这叫不叫资源竞争?因为不在同一时间运行期间实际上是交互进行的,但是因为偏向锁默认条件下是不会主动释放的。在偏向锁上锁流程是通过CAS将当前线程写入markword的,在写入之前是会进行对比锁对象markword是否是当前线程的。如果是和当前线程id一致的话,只会在计数器上加1 ,用于实现可重入式锁。
  • 如果是第二个线程不管是不是同时都会发生线程id不一致情况。这个时候就会发生偏向锁升级成轻量级锁。这个升级的过程也是很麻烦的过程。JVM实际上需要找到安全点(即线程不活动时间点)先撤销偏向锁,然后在上轻量级锁

偏向锁图示

轻量级锁图示

  • 通过图示我们也能够看的出来,偏向锁只会发生一次CAS, 而轻量级锁会无时无刻不发生CAS , 我们要知道CAS引发的线程自旋也是耗费CPU调度的,因为线程都处于活跃状态,那么CPU就会发生线程调度切换。所以在并发不是很高和普遍的项目中偏向锁是很搞笑的。
 ​
 class User{
     String userName;
 }
 public class SoftLock {
     public static void main(String[] args) throws InterruptedException {
         User user = new User();
         System.out.println("加锁前(禁用偏向延迟,此时应该是偏向锁默认):"+ClassLayout.parseInstance(user).toPrintable());
         final Thread t1 = new Thread(new Runnable() {
             @Override
             public void run() {
                 synchronized (user) {
                     System.out.println("t1加锁中:" + ClassLayout.parseInstance(user).toPrintable());
                }
            }
        });
         t1.start();
         t1.join();
         final Thread t2 = new Thread(new Runnable() {
             @Override
             public void run() {
                 synchronized (user) {
                     System.out.println("t1加锁中,因为t1加锁后线程偏向锁不会释放,所以t2会发生偏向锁撤销,最终t2轻量级锁:" + ClassLayout.parseInstance(user).toPrintable());
                }
            }
        });
         t2.start();
         t2.join();
         System.out.println("加锁后(无锁):"+ClassLayout.parseInstance(user).toPrintable());
    }
 }
  • 上述代码我们能够看出,在t2线程中尝试加锁就会变成轻量级锁。轻量级锁和偏向锁不同的是,轻量级锁使用后会释放锁,变成无锁状态
  • 当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。
  • 在代码进入同步块的时候,如果同步对象锁状态为无锁状态(锁标志位为“01”状态,是否为偏向锁为“0”),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,然后拷贝对象头中的Mark Word复制到锁记录中。
  • 拷贝成功后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针,并将Lock Record里的owner指针指向对象的Mark Word。
  • 如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位设置为“00”,表示此对象处于轻量级锁定状态。
  • 如果轻量级锁的更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行,否则说明多个线程竞争锁。
  • 若当前只有一个等待线程,则该线程通过自旋进行等待。但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁升级为重量级锁。
  • 多个线程在不同的时间段请求同一把锁,也就是说没有锁竞争。针对这种情形,Java 虚拟机采用了轻量级锁,来避免重量级锁的阻塞以及唤醒
  • 轻量级锁的条件是发生竞争或者是不得不上轻量级锁。下面我们看一种不得不上轻量级锁的案列 , 注意VM属性开启偏向锁延迟 及VM不做任何配置
 public class SimpleTest {
     public static void main(String[] args) {
         SimpleTest test = new SimpleTest();
         System.out.println(ClassLayout.parseInstance(test).toPrintable());
         synchronized (test) {
             System.out.println(ClassLayout.parseInstance(test).toPrintable());
        }
    }
 }
  • 这段代码和上面偏向锁演示匿名偏向锁的代码是一样的,不同的是VM的配置取消了。也就是开启了偏向锁延迟。那么我们第一次打印的test对象中markword中是无锁状态。按理说第二次就应该上偏向锁了。但是我们试想一下在第二次上偏向锁的时候延迟偏向也有可能会上偏向锁,这不就发生了资源争抢了吗,为了避免和延迟偏向发生冲突,所以第二次直接是轻量级锁。

后续迭代推出重量级锁。

synchronized已经不在臃肿了,放下对他的成见之初识轻量级锁的更多相关文章

  1. JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

    JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程 ...

  2. Synchronized锁性能优化偏向锁轻量级锁升级 多线程中篇(五)

    不止一次的提到过,synchronized是Java内置的机制,是JVM层面的,而Lock则是接口,是JDK层面的 尽管最初synchronized的性能效率比较差,但是随着版本的升级,synchro ...

  3. Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  4. synchronized底层实现原理&CAS操作&偏向锁、轻量级锁,重量级锁、自旋锁、自适应自旋锁、锁消除、锁粗化

    进入时:monitorenter 每个对象有一个监视器锁(monitor).当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:1 ...

  5. java 偏向锁、轻量级锁及重量级锁synchronized原理

    Java对象头与Monitor java对象头是实现synchronized的锁对象的基础,synchronized使用的锁对象是存储在Java对象头里的. 对象头包含两部分:Mark Word 和 ...

  6. JVM内部细节之一:synchronized关键字及实现细节(轻量级锁Lightweight Locking)

    在C程序代码中我们可以利用操作系统提供的互斥锁来实现同步块的互斥访问及线程的阻塞及唤醒等工作.然而在Java中除了提供Lock API外还在语法层面上提供了synchronized关键字来实现互斥同步 ...

  7. 【转载】Java中的锁机制 synchronized & 偏向锁 & 轻量级锁 & 重量级锁 & 各自优缺点及场景 & AtomicReference

    参考文章: http://blog.csdn.net/chen77716/article/details/6618779 目前在Java中存在两种锁机制:synchronized和Lock,Lock接 ...

  8. 并发-Synchronized底层优化(偏向锁、轻量级锁)

    Synchronized底层优化(偏向锁.轻量级锁) 参考: http://www.cnblogs.com/paddix/p/5405678.html 一.重量级锁 上篇文章中向大家介绍了Synchr ...

  9. 【转】Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

     一.重量级锁 上篇文章中向大家介绍了Synchronized的用法及其实现的原理.现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本 ...

随机推荐

  1. TCP/IP详解 读书笔记(一):概述

    分层 网络协议通常分不同层次进行开发,每一层负责不同的职责,一个协议簇指的是一组不同层次上的多个协议的组合. TCP/IP通常被认为是一个四层协议系统: 链路层:主要是处理与电缆或其他传输媒介的物理接 ...

  2. 阿里云K8S节点NotReady状态

    开发部署pod的时候在wayne平台上部署不上去,删除也删除不了 先删除 kubectl delete pod pod-name --grace-period=0 --force 删除之后然后部署新的 ...

  3. 内网安全之横向移动(冰蝎&&msf&&IPC$)

    1.冰蝎介绍 冰蝎是一款目前比较流行的Webshell管理工具,在2021年更新的2021.4.20 v3.0 Beta 9 版本中去除了动态密钥协商机制,采用预共享密钥,载荷全程无明文.因其优秀的加 ...

  4. [题解]UVA10986 Sending email

    链接:http://vjudge.net/problem/viewProblem.action?id=24941 描述:n个点,m条边的无向图,寻找从S到T的最短路. 思路:基础的单源点最短路 用Di ...

  5. 年底获奖人太多?奖状可以用Smartbi电子表格这么做!

    又到一年年终时,你的年终奖到手了吗?奖金没领到,发个奖状压压惊 今天给大家分享年终奖相关的年终奖状的批量套打功能,保证你的奖状及时到手! 示例说明 现有多个人员的奖励需要通知,需要生成可翻页的奖状.并 ...

  6. LSMT 实战-python

    长短期记忆网络(LSTM,Long Short-Term Memory) 使用kears 搭建一个LSTM预测模型,使用2022年美国大学生数学建模大赛中C题中处理后的BTC比特币的数据进行数据训练和 ...

  7. 【C# TAP 异步编程】一 、async 修饰符(标记)

    async的作用: 1.async是一个标记,告诉编译器这是一个异步方法. 2.编译器会根据这个标志生成一个异步状态机. 3.编译器将原异步方法中的代码清空,写入状态机的配置,原先异步方法中的代码被封 ...

  8. centos7 部署ansible

    Ansible默认采用SSH的方式管理客户端,基于python开发,由paramiko和PyYAMl 两个关键模块构建 支持非root用户管理,支持sudo ansible作用:通过使用ansible ...

  9. FoveaBox:细节差别,另一种DenseBox+FPN的Anchor-free方案 | IEEE TIP 2020

    作为与FCOS和FSAF同期的Anchor-free论文,FoveaBox在整体结构上也是基于DenseBox加FPN的策略,主要差别在于FoveaBox只使用目标中心区域进行预测且回归预测的是归一化 ...

  10. 『现学现忘』Docker相关概念 — 3、IaaS、SaaS、PaaS服务模式补充

    目录 1.IaaS服务模式 2.PaaS服务模式 (1)何时使用PaaS (2)PaaS的特点 (3)PaaS优势 3.SaaS服务模式 云计算通俗来说就是输入/输出和计算不在一个主机上.计算要用到计 ...