java并发机制的底层实现原理
博客专区 > getqiu 的博客 > 博客详情
java并发机制的底层实现原理
getqiu 发表于1年前
java并发机制的底层实现原理
  • 发表于 1年前
  • 阅读 19
  • 收藏 1
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

[TOC]

volatile的应用

volatile定义与实现原理

如果一个字段被申明为volatile,Java线程内存模型确保所有的线程看到这个变量的值是一致的。

具体来讲volatile的两条实现原则:

  • 1.Lock前缀指令会引起处理器缓存回写到内存。

  • 2.一个处理器的缓存回写到内存会导致其它处理器的缓存无效。

synchronized的实现原理与应用

并发编程当中,大多数时候都认为它为重量级锁。但是JDK1.6之后对synchronized进行了各种优化,引入了偏向锁和轻量级锁。

Java对象头

synchronized用的锁是存在Java对象头里的。

|代表状态 |存储内容 |标志位 |

|-------------------|--------------------------------------------|-----------|

|未锁定 |对象hash码,对象分代年龄 |01 |

|轻量级锁定 | 指向锁记录的指针 |00 |

|膨胀(重量级锁定)| 指向重量级锁的指针 |10 |

| GC标记 | 空,不需要记录信息 |11 |

|可偏向 | 偏向线程ID,偏向时间戳,对象年龄|01 |

锁升级与对比

Java6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”,锁一共有4中状态:无锁状态,偏向锁,轻量级锁和重量级锁。这4中状态会随着竞争的情况逐渐升级。锁可以升级,但是不能降级。

偏向锁

大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入偏向锁。

偏向锁设置

当一个线程访问同步块并获取锁时,会在对象头栈帧中的锁记录里存储偏向的线程ID。

以后该线程进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需要简单的测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果测试成功表示线程已经获得锁。

如果测试失败:则需要再测试一下Mark Word中偏向锁的标识是否被设置称为了1(标识当前是偏向锁)

如果没有设置,则使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指针指向当前线程。

偏向锁的撤销

偏向锁使用了一种等到竞争出现才释放锁的机制。所以当其它线程尝试竞争偏向锁是,持有偏向锁的线程才会释放锁。

偏向锁的撤销,需要等待全局安全点(这个点上没有正在执行的字节码)。

首先暂停拥有偏向锁的线程,然后检查持有偏向锁的线程是否存活,如果线程任然活着,那么这个线程将继续执行,遍历偏向对象的锁记录、栈中的锁记录和对象头Mark Word,要么重新偏向于其它线程,要么恢复到无锁活着标记为不适合作为偏向锁。

关闭偏向锁

偏向锁在Java6以上是默认开启的,但是它在应用程序启动几秒以后才激活,如果必要可以使用JVM参数来关闭延迟:-XX:BiasedLockingStartupDelay=0,如果程序当中的线程通常情况下处于竞争状态,可以通过JVM参数关闭偏向锁-XX:UseBiasedLocking=false

轻量级锁

轻量级锁加锁

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

轻量级锁解锁

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

原子操作的实现原理

原子操作(atomic operation)意思为:不可被中断的一个或一系列操作。

标签: java并发
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 1
博文 12
码字总数 11145
×
getqiu
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: