• Tags
  •         
  • www.breakyizhan.com
  •    

    Java锁的种类:偏向锁,轻量级锁和重量级锁

    我们在Java的并发编程:从synchronized保证线程安全的原理 这篇文章中,已经说到了synchronized可以用锁来保证线程的安全问题,那么,我们这一节要说的就是锁的分类。以前是只有重量级锁这个分类,但是自从JDK6引入了偏向锁和轻量级锁之后,锁的种类就有下面三种了:

      • 偏向锁
      • 轻量级锁
      • 重量级锁

    Java锁存储的地方

    任何对象都可以作为锁,那么锁信息又存在对象的什么地方呢?Java的锁存在对象头中,具体位置是对象头中的Mark Word。具体对象的头信息有:

    • Mark Word (Java的锁信息)
    • Class Metadata Address
    • Array Length

    那么Java的锁信息主要存储下面这些内容:

    • 线程id
    • Epoch
    • 对象的分代年龄信息
    • 是否是偏向锁
    • 锁标志位

    锁标志位主要就是用来分类锁的种类。

    偏向锁,轻量级锁和重量级锁

    为了换取性能,JVM在内置锁上做了非常多的优化。理解偏向锁、轻量级锁、重量级锁的要解决的基本问题,几种锁的分配和膨胀(升级)过程,有助于编写并优化基于锁的并发程序。

    Java的偏向锁

    偏向锁的目标是,减少无竞争且只有一个线程使用锁的情况下,使用轻量级锁产生的性能消耗。主要有下面这些特点:

    • 每次获取锁和释放锁会浪费资源
    • 很多情况下,竞争锁不是由多个线程,而是由一个线程在使用。
    • 只有一个线程在访问同步代码块的场景

    当然了,如果明显存在其他线程申请锁,那么偏向锁将很快升级为轻量级锁。

    Java的轻量级锁

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

    轻量级锁的加锁:

    如果成功使用CAS将对象头重的Mark Word替换为指向锁记录的指针,则获得锁,失败则当前线程尝试使用自旋(循环等待)来获取锁。

    轻量级锁的解锁:

    当有另一个线程与该线程同时竞争时,锁会升级为重量级锁。为了防止继续自旋,一旦升级,将无法降级。

    Java的重量级锁

    重量级锁特点:

    其他线程试图获取锁时,都会被阻塞,只有持有锁的线程释放锁之后才会唤醒这些线程,进行竞争。

     
    转载请保留页面地址:https://www.breakyizhan.com/java/6631.html