Java 多线程之:偏向锁,轻量级锁,重量级锁

  • 一:java多线程互斥,和java多线程引入偏向锁和轻量级锁的缘由?

--->synchronized的重量级别的锁,就是在线程运行到该代码块的时候,让程序的运行级别从用户态切换到内核态,把全部的线程挂起,让cpu经过操做系统指令,去调度多线程之间,谁执行代码块,谁进入阻塞状态。这样会频繁出现程序运行状态的切换,线程的挂起和唤醒,这样就会大量消耗资源,程序运行的效率低下。为了提升效率,jvm的开发人员,引入了偏向锁,和轻量级锁,尽可能让多线程访问公共资源的时候,不进行程序运行状态的切换,由用户态进入内核态,借助操做系统进行互斥。
 
--->jvm规范中能够看到synchronized在jvm里实现原理,jvm基于进入和退出Monitor对象来实现方法同步和代码块同的。在代码同步的开始位置织入monitorenter,在结束同步的位置(正常结束和异常结束处)织入monitorexit指令实现。线程执行到monitorenter处,讲会获取锁对象锁对应的monitor的全部权,即尝试得到对象的锁。(任意对象都又一个monitor与之关联,当且一个monitor被持有后,他处于锁定状态)
 
--->java的多线程安全是基于lock机制实现的,而lock的性能每每不如人意。缘由是,monitorenter与monitorexit这两个控制多线程同步的bytecode原语,是jvm依赖操做系统互斥(mutex)来实现的。
 
--->互斥是一种会致使线程挂起,并在较短期内又须要从新调度回原线程的,较为消耗资源的操做。
 
--->为了优化java的Lock机制,从java6开始引入轻量级锁的概念。轻量级锁本意是为了减小多线程进入互斥的概率,并非要替代互斥。它利用了cpu原语Compare-And-Swap(cas,汇编指令CMPXCHG),尝试进入互斥前,进行补救。
 
 
  • 五:偏向锁,轻量级锁,重量级锁对比

优势 缺点 适用场景
偏向锁 加锁和解锁不须要额外的消耗,和执行非同步方法相比仅存在纳秒级的差距 若是线程间存在锁竞争,会带来额外的锁撤销的消耗 适用于只有一个线程访问同步块场景
轻量级锁 竞争的线程不会阻塞,提升了程序的响应速度 若是始终得不到索竞争的线程,使用自旋会消耗CPU 追求响应速度,同步块执行速度很是快
重量级锁 线程竞争不使用自旋,不会消耗CPU 线程阻塞,响应时间缓慢 追求吞吐量,同步块执行速度较长

 

对象头的存储内容(monitor)java

 

长度 内容 说明
32/64bit Mark Word 存储对象的hashcode或锁信息
32/64bit 类对象的地址 存储到对象类型数据的指针
32/64bit Array length 数组的长度(若是当前对象是数组)
Mark Word存储内容(monitor)的状态变化

 

锁状态 25bit,4bit 1bit(是不是偏向锁) 2bit(锁标示位)
轻量级锁 指向栈中锁记录的指针   00
重量级锁 指向互斥量(重量级锁)的指针   10
 GC   11
偏向锁 线程id,对象hashcode,对象分代年龄 1 01

 

  • 六:锁的状态

--->锁一共有四种状态(由低到高的次序):无锁状态,偏向锁状态,轻量级锁状态,重量级锁状态
--->锁的等级只能够升级,不能够降级。这种锁升级却不能降级的策略,目的是为了提升得到锁和释放锁的效率。
 
 
  • 七:偏向锁

--->a线程得到锁,会在a线程的的栈帧里建立lock record(锁记录变量),则在锁对象的对象头里和lock record里存储a线程的线程id.之后该线程的进入,就不须要cas操做,只须要判断是不是当前线程。
--->a线程获取锁,不会释放锁。直到b线程也要竞争该锁时,a线程才会释放锁。
--->偏向锁的释放,须要等待全局安全点(在这个时间点上没有正在执行的字节码),它会首先暂停拥有偏向锁的线程,而后检查持有偏向锁的线程是否还活着,若是线程不处于活动状态,则将对象头设置成无锁状态。若是线程仍然活着,拥有偏向锁的栈会被执行,遍历偏向对象的所记录。栈帧中的锁记录和对象头的Mark Word要么从新偏向其余线程,要么恢复到无锁,或者标记对象不适合做为偏向锁。最后唤醒暂停的线程。
--->关闭偏向锁,经过jvm的参数-XX:UseBiasedLocking=false,则默认会进入轻量级锁。
 
  • 八:轻量级锁

--->a线程得到锁,会在a线程的栈帧里建立lock record(锁记录变量),让lock record的指针指向锁对象的对象头中的mark word.再让mark word 指向lock record.这就是获取了锁。
--->轻量级锁,b线程在锁竞争时,发现锁已经被a线程占用,则b线程不进入内核态,让b线程自旋,执行空循环,等待a线程释放锁。若是,完成自旋策略仍是发现a线程没有释放锁,或者让c线程占用了。则b线程试图将轻量级锁升级为重量级锁。
 
 
  • 九:重量级锁

--->重量级锁,就是让争抢锁的线程从用户态转换成内核态。让cpu借助操做系统进行线程协调。
相关文章
相关标签/搜索