zoukankan      html  css  js  c++  java
  • synchronized的实现原理

    Synchronized的特性

    synchronized 是java中的关键字,主要用于加锁,来实现同步,具体实现形式有以下三种:

    1.对普通方法加锁,锁是当前实例对象

    2.对静态方法加锁,锁是当前类的Class实例,因为Class数据存在于永久代,因此静态方法锁相当于该类的一个全局锁;

    3.对对象实例加锁,锁是Synchronized括号里对象实例。

    synchronized 内置锁 是一种 对象锁(锁的是对象而非引用变量),作用粒度是对象 可以用来实现对临界资源的同步互斥访问 ,是可重入的。其可重入最大的作用是避免死锁,如:子类同步方法调用了父类的同步方法,如果没有可重入的特性,就会发生死锁。

    Synchronized的同步实现

    Synchronized的锁的实现是基于JVM进入和退出monitor对象来实现的。

    monitor对象有2个关键指令monitorenter和monitorexit,具体就是在编译过程中把monitorenter指令插入到同步代码块开始位置,把monitorexit指令插入退出或异常的位置。

    线程执行同步代码块的时首先需要获取锁,即尝试获取monitor对象的所有权,具体过程如下:

    首先线程执行指令monitorenter指令尝试获取monitor的所有权,如果monitor的进入数为0,则线程进入进入monitor,并且把进入修改为1,当前线程就持有了锁;如果线程进入monitor时,发现进入数大于0,则会判断monitor的持有者是否为当前线程,如果是当前线程则表示只是重新进入,则对monitor的进入数+1;如果monitor的所有权不是被当前线程持有,线程进入阻塞状态,直到monitor的进入数等于0,再次重新获取monitor的所有权。

    对象头

    java中每个对象都包含三部分:对象头、实例数据、对齐填充(非必须)。synchronized使用的锁是存在对象的对象头中,对象头主要包含了2部分数据,Mark Word(存储对象的hashCode、分代年龄和锁标记位)、Class Metadata Address(存储对象类型数据的指针)。

    锁的升级和对比

    synchronized在JDK 1.6以后引入锁的状态级别,从低到高为:无锁、偏向锁、轻量级锁、重量级锁;

    锁可以根据竞争进行粗话升级,但是不能降级。

    偏向锁

    当一个线程访问同步代码块获取锁时,会在对象头和栈帧中的锁记录中存储锁偏向的线程id,以后该线程再次进入和退出同步代码块时不需要信息CAS操作来加锁或解锁。

    首先执行monitorenter命令尝试获取锁,查询Mark Word中存储的线程id是否为当前线程id,如果为当前线程id,则直接执行同步代码,如果不是当前线程id,则判断是否开启了偏向锁;

    当偏向锁标识为1是,使用CAS竞争锁,竞争成功,尝试把Mark Word中的偏向锁指向自己;竞争失败,表示当前有多个线程在竞争锁,当到达全局安全点时,获得偏向锁的线程被挂起,偏向锁升级为轻量级锁,然后被阻塞在安全点的线程继续往下执行同步代码块;

    偏向锁的机制:竞争时才会释放锁,线程是不会主动去释放偏向锁,需要等待其他线程来竞争。偏向锁的撤销需要 等待全局安全点(这个时间点是上没有正在执行的代码)

    轻量锁

    轻量锁加锁

    线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为DisplacedMark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

    轻量锁解锁

    轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。

     因为自旋会消耗CPU,为了避免无用的自旋(比如获得锁的线程被阻塞住了),一旦锁升级成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时,都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮的夺锁之争。

  • 相关阅读:
    HDU 4348 To the moon(可持久化线段树)
    HDU 5875 Function 大连网络赛 线段树
    HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)
    HDU 5876 大连网络赛 Sparse Graph
    HDU 5701 中位数计数 百度之星初赛
    CodeForces 708B Recover the String
    Java实现 蓝桥杯 算法提高 套正方形(暴力)
    ASP.NET生成验证码
    ASP.NET生成验证码
    ASP.NET生成验证码
  • 原文地址:https://www.cnblogs.com/wangzun/p/13454495.html
Copyright © 2011-2022 走看看