synchronized原理

   synchronized是单服务器常用的同步机制,可是具体的原理又有多少人能说清呢?

   synchronized既可以用于同步一个代码块,又可以同步一个类和方法:

   当作用于一个静态类时,所有调用到静态类的地方都会被同步;

   当作用于一个普通类时,所有调用到类实例的地方会被同步;

   当同步于一个方法区时,所有调用到括号中的对象会被同步;

     

      JVM中是通过进入和退出Monitor对象来实现线程同步的,对于同步方法区来说,主要是通过monitorenter 和monitorexit指令来实现的,而方法同步的则是通过另一种方式实现的,当然也可以用monitorenter 和monitorexit来实现。   monitorenter指令是在编译后插入方法区开头,monitorexit指令是插入到方法结束处或者异常处,JVM要求monitorenter和monitorexit都必须成对出现。

      每个对象都有一个monitor与之关联,当线程持有该monitor时,其它线程无法访问对象。synchronized 对象用到的锁是存在Java对象头中的,32位虚拟机中,Java对象头结构一般如下

长度   内容   说明
32bit Mark Word 对象的hashCode或者锁信息
32bit Class Metadata Address 存储到对象类型数据的指针
32bit Array length 数组长度(如果是数组)

  

       其中Mark Word存储格式如下

锁状态   25bit 4bit 1bit是否偏向锁 2bit 锁标识

无锁/偏向锁/

轻量级锁/重量级锁

对象hashcode  对象分代年龄  0  

00-轻量级锁

01-偏向锁

10-重量级锁

11-GC标识

  •         偏向锁

   当某个线程1访问同步块时,如果对象头没有存储当前线程,则通过CAS替换Mark word,如果替换成功,则将对象头Mark word线程ID指向自己,这时候如果另一个线程2开始访问同步块,则CAS替换Mark word会失败,线程2则会撤销偏向锁暂停线程。线程1执行完同步块后会释放锁,将Mark word中的线程ID设为空,其它线程可进行访问同步块。

  •         轻量级锁/重量级锁 

      与偏向锁通过控制Mark word指向线程ID的方式不同,轻量级锁实现原理如下:

      当线程访问同步块时,会在线程的栈桢中创建锁记录空间,将对象头中的Mark word复制到锁记录中。当线程访问同步块时,会使用CAS将对象头中的 Mark word复制到自己线程的锁记录空间中,当获取成功后,当前线程获取到锁,如果失败,则说明线程已被其他线程竞争得到,当前线程会通过自旋获取锁。竞争锁成功的线程在执行完同步块后会通过CAS替换Mark word,当替换失败后,表明当前锁存在竞争,锁将会自动升级为重量级锁,其余通过自旋竞争锁的线程将被阻塞,直至锁释放后被唤醒。

原文地址:https://www.cnblogs.com/toDjlPersonnalBlog/p/8280961.html