JavaConcurrentJVM

Java并发 锁优化和锁升级

2019-03-19  本文已影响0人  baiiu

前言

本篇文章介绍Java Synchronized锁优化。

  1. 锁是存在哪里的,怎么标识是什么锁
  2. Monitor机制在Java中怎么表现的
  3. 锁优化
  4. 锁升级

1. 锁存在哪里

JVM中对象头的方式有以下两种(以32位JVM为例):

// 普通对象
|--------------------------------------------------------------|
|                     Object Header (64 bits)                  |
|------------------------------------|-------------------------|
|        Mark Word (32 bits)         |    Klass Word (32 bits) |
|------------------------------------|-------------------------|

// 数组对象
|---------------------------------------------------------------------------------|
|                                 Object Header (96 bits)                         |
|--------------------------------|-----------------------|------------------------|
|        Mark Word(32bits)       |    Klass Word(32bits) |  array length(32bits)  |
|--------------------------------|-----------------------|------------------------|
|-------------------------------------------------------|--------------------|
|                  Mark Word (32 bits)                  |       State        |
|-------------------------------------------------------|--------------------|
| identity_hashcode:25 | age:4 | biased_lock:0 |lock:01 |     Normal无锁      |
|-------------------------------------------------------|--------------------|
|  thread:23 | epoch:2 | age:4 | biased_lock:1| lock:01 |     Biased偏向锁    |
|-------------------------------------------------------|--------------------|
|               ptr_to_lock_record:30         | lock:00 | Lightweight Locked轻量级锁 |
|-------------------------------------------------------|--------------------|
|               ptr_to_heavyweight_monitor:30 | lock:10 | Heavyweight Locked重量级锁 |
|-------------------------------------------------------|--------------------|
|                                             | lock:11 |    Marked for GC   GC标记|
|-------------------------------------------------------|--------------------|
锁状态

2. Monitor机制

Monitor其实是一种同步工具、同步机制,在Java中,Object 类本身就是监视者对象,Java 对于 Monitor Object 模式做了内建的支持,即每一个Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质。
并且同时只能有一个线程可以获得该对象monitor的所有权。在线程进入时通过monitorenter尝试取得对象monitor所有权,退出时通过monitorexit释放对象monitor所有权。

Monitor 是线程私有的数据结构,每一个线程都有一个可用monitor record列表,同时还有一个全局的可用列表。
每一个被锁住的对象都会和一个monitor关联(对象头的MarkWord中的LockWord指向monitor的起始地址),同时monitor中有一个Owner字段存放拥有该锁的线程的唯一标识,表示该锁被这个线程占用。

Monitor Record列表

3. 锁优化

jdk1.6对锁的实现引入了大量的优化,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。
锁主要存在四中状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,他们会随着竞争的激烈而逐渐升级。
其中锁可以升级不可降级,这种策略是为了提高获得锁和释放锁的效率。

1. 重量级锁

monitor 监视器锁本质上是依赖操作系统的 Mutex Lock 互斥量 来实现的,我们一般称之为重量级锁。因为 OS 实现线程间的切换需要从用户态转换到核心态,这个转换过程成本较高,耗时相对较长,因此 synchronized 效率会比较低。

2. 轻量级锁

轻量级锁,其性能提升的依据是对于绝大部分的锁,在整个生命周期内都是不会存在竞争的,如果没有竞争,轻量级锁就可以使用 CAS 操作避免互斥量的开销,从而提升效率。
如果打破这个依据则除了互斥的开销外,还有额外的CAS操作,因此在有多线程竞争的情况下,轻量级锁比重量级锁更慢。

3. 偏向锁

依据:对于绝大部分锁,在整个同步周期内不仅不存在竞争,而且总由同一线程多次获得。
在一些情况下总是同一线程多次获得锁,此时第二次再重新做CAS修改对象头中的Mark Word这样的操作,有些多余。所以就有了偏向锁,只需要检查是否为偏向锁、锁标识为以及ThreadID即可,只要是同一线程就不再修改对象头。其目的为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径。

4. 总结

锁主要存在四中状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,其升级如下图所示:


锁升级.png 优缺点

其他优化

public String concatString(String s1, String s2, String s3) {
    StringBuffer sb = new StringBuffer();
    sb.append("a");
    sb.append("b");
    sb.append("c");
    return sb.toString();
}

结语

本篇文章介绍了JVM对Synchronized进行的锁优化。自旋到自适应自旋、锁消除和锁粗化,从无锁到偏向锁、轻量级锁,都在避免线程进入内核态进行的切换。针对各种情况做的优化,

参考:
Java对象头详解
如何正确计算Java对象所占内存?

Java Synchronised机制
深入分析synchronized的实现原理
synchronized和锁优化
Java synchronized 关键字的实现原理

上一篇 下一篇

猜你喜欢

热点阅读