面试中多次被问到synchronized关键字的实现原理,一直认为仅是monitorenter与monitorexit两条指令而已,原来底层涉及到多种锁优化策略,包括:自旋锁,轻量锁,偏向锁。

1、自旋锁

互斥同步对性能影响最大的部分是线程的阻塞与恢复,因为这两个操作涉及用户态与内核态的转换。如果共享数据锁定时间很短,而且竞争不是特别激烈,那么阻塞实现并不划算。因此在多核的处理器中,我们可以让请求锁的线程进行忙等,而不是放弃处理器执行时间。反之,如果锁占用时间比较长,那忙等的线程只会白白浪费处理器资源,因此需要有一定的时间限制,超出限制便挂起线程。

使用AtomicReference模拟自旋锁:

public class SpinLock {

  private AtomicReference<Thread> sign =new AtomicReference<>();

  public void lock(){
Thread current = Thread.currentThread();
while(!sign .compareAndSet(null, current));
} public void unlock (){
Thread current = Thread.currentThread();
sign .compareAndSet(current, null);
}
}

2、轻量锁

轻量锁是相对于阻塞实现的重量锁而言的,很多时候虽然用到锁,但并不存在竞争情况,相当于多个线程轮流获取一把锁。轻量锁可使用CAS操作获取,被多线程竞争时会膨胀为重量锁。

每个对象的对象头中都有一个字,称为mark word,低两位代表状态,根据状态的不同,其余各位有不同的含义:

HotSpot虚拟机以一种叫做displaced headers的方法实现轻量锁。当线程获取轻量锁时,会在该线程的栈上创建一个lock record(lock record由一个mark word备份,一个指向对象的指针组成),然后备份当前mark word,最后使用CAS操作把mark word的状态位更新为Thin locked,也就是00,同时mark word中的指针指向lock record。

发生重入时,线程可以知道对象mark word中的指针正指向自己的栈,便创建一个值为NULL的lock record,在释放锁时如果lock record值为NULL就立即返回。

当轻量锁被一个线程获得后,另一个希望获取锁的线程会将轻量锁膨胀为重量锁,该线程在一个循环里不断尝试,直到膨胀成功。膨胀也会发生在锁的wait或notify方法被调用时,无论该锁是否已被一个线程获取。

进行膨胀时,首先用CAS将mark word中的状态位更新为Inflating,尝试获取处于该状态锁的线程会等待到膨胀完成,已经获取到锁的线程也必须等到膨胀完成才能释放锁。

3、偏向锁

前文说到轻量锁适合的场景是多个线程轮流占用资源,而偏向锁适用的场景是一个线程反复占用资源。什么时候会出现这种情况呢?比如在使用一些类库时,它的接口是线程安全的,但我们不会通过多个线程访问。

在Unlocked状态下,mark word的第三位代表是否允许启用偏序。如果那一位为0,说明锁没有被任何线程获取,且不允许偏序。如果为1,锁可以是如下状态中的一种:

  • 匿名偏向:线程指针为NULL,锁还没有偏向于任何一个线程,这是允许偏向的锁的初始状态。
  • 可重偏向:mark word中的epoch字段无效,获取锁的线程可使锁偏向自己。
  • 已偏向:线程指针不为NULL,epoch字段有效,锁正偏向于线程指针指向的线程。

由于偏向锁需要占用hashcode字段存放线程指针,访问该对象的hashcode将会导致偏向状态被撤销(Object类的hashcode的方法会导致这种情况)。

偏向锁使用的lock record与轻量锁一致,但是mark word备份没有被使用,在偏向被撤销时,会被转化为轻量锁。

偏序撤销在系统到达全局安全点时执行,竞争线程通过遍历偏序线程的lock record判断锁是否正在被占用, 将其转化为轻量锁或偏向自己。

参考:《Evaluating and improving biased locking in the HotSpot virtual machine》

HotSpot虚拟机的锁优化的更多相关文章

  1. 深入理解多线程(五)—— Java虚拟机的锁优化技术

    本文是<深入理解多线程>的第五篇文章,前面几篇文章中我们从synchronized的实现原理开始,一直介绍到了Monitor的实现原理. 前情提要 通过前面几篇文章,我们已经知道: 1.同 ...

  2. Java 虚拟机对锁优化所做的努力

    作为一款公用平台,JDK 本身也为并发程序的性能绞尽脑汁,在 JDK 内部也想尽一切办法提供并发时的系统吞吐量.这里,我将向大家简单介绍几种 JDK 内部的 "锁" 优化策略. 1 ...

  3. Java虚拟机对锁优化所做的努力(读书笔记)

    锁偏向      是一种加锁操作的优化手段,他的核心思想是:如果一个线程获得了锁,那么就进入偏向模式,当这个线程再次请求锁时,无须在做任何同步操作,因此在几乎没有锁竞争的场合,偏向锁是比较好的优化效果 ...

  4. Java虚拟机的锁优化

    1 锁偏向.当现成请求一个对象锁时,如果获得锁,则该对象锁进入偏向模式,当该线程再次请求该对象的锁时,无需再做任何同步操作. 可通过在Java虚拟机中开启参数-XX:+UseBasedLock开启偏向 ...

  5. 《深入理解Java虚拟机》-----第13章 线程安全与锁优化

    概述 在软件业发展的初期,程序编写都是以算法为核心的,程序员会把数据和过程分别作为独立的部分来考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据,这种思维方式直接站在计算机的角度去抽象问题和解 ...

  6. 《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化

    <深入了解java虚拟机>高效并发读书笔记--Java内存模型,线程,线程安全 与锁优化 本文主要参考<深入了解java虚拟机>高效并发章节 关于锁升级,偏向锁,轻量级锁参考& ...

  7. Java虚拟机13:互斥同步、锁优化及synchronized和volatile

    互斥同步 互斥同步(Mutual Exclusion & Synchronization)是常见的一种并发正确性保证手段.同步是指子啊多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一 ...

  8. 深入理解java虚拟机(7)---线程安全 & 锁优化

    关于线程安全的话题,足可以使用一本书来讲解这些东西.<Java Concurrency in Practice> 就是讲解这些的,在这里 主要还是分析JVM中关于线程安全这块的内容. 1. ...

  9. 深入理解Java虚拟机读书笔记9----线程完全与锁优化

    九 线程完全与锁优化   1 Java语言中的线程完全         ---线程安全:当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用 ...

随机推荐

  1. 大数据 -- Hadoop集群环境搭建

    首先我们来认识一下HDFS, HDFS(Hadoop Distributed File System )Hadoop分布式文件系统.它其实是将一个大文件分成若干块保存在不同服务器的多个节点中.通过联网 ...

  2. XT交易所Websocket API

    WebSocketAPI xt为用户提供了一个简单的而又强大的API,旨在帮助用户快速高效的将xt交易功能整合到自己应用当中. WebSocket服务地址 xt WebSocket服务连接地址:wss ...

  3. windows mysql手动添加my.ini 服务启动不了

    [mysqld] character-set-server=utf8 #绑定IPv4和3306端口 bind-address=0.0.0.0 port= default_storage_engine= ...

  4. nginx添加sticky模块-cookie保持会话

    cookie不同于session,一个存于客户端,一个存于服务端. 环境nginx 1.8.0 centos6.X sticky:1.2.5  wget https://bitbucket.org/n ...

  5. 晶体管放大电路与Multisim仿真学习笔记

    前言 开始写点博客记录学习的点滴,第一篇就写基本的共射极放大电路吧. 很多教材都是偏重理论,而铃木雅臣著作的<晶体管电路设计>是一本很实用的书籍,个人十分推荐! 下面开始我的模电重温之旅吧 ...

  6. (CSDN迁移) JAVA多线程实现-实现Runnable接口

    实现Runnable接口  implements Runnable 重写run()方法 @Override public void run(){//TODO} 创建线程对象: Thread threa ...

  7. LeNet-5 卷积神经网络结构图

    LeNet-5是Yann LeCun在1998年设计的用于手写数字识别的卷积神经网络,当年美国大多数银行就是用它来识别支票上面的手写数字的,它是早期卷积神经网络中最有代表性的实验系统之一.可以说,Le ...

  8. Opencv颜色识别与追踪

    这是基于颜色识别的物体追踪 不废话 直接看代码 这是Opencv3的代码 //---------------------------------[头文件.命名空间包含部分]-------------- ...

  9. rancher部署kubernets集群

    docker的安装 先添加docker源 sudo apt update sudo apt install docker.io docker更换国内镜像 1.配置脚本如下: #!/bin/bashca ...

  10. 强大的Grafana k8s 插件

    原文参考: https://i4t.com/4152.html 参考:https://blog.csdn.net/mailjoin/article/details/81389700 插件链接:http ...