Android开发Android开发Android技术知识

要点提炼| 理解JVM之线程安全&锁优化

2018-07-19  本文已影响68人  厘米姑娘

本篇将介绍线程安全所涉及的概念和分类、同步实现的方式及虚拟机的底层运作原理,以及虚拟机为了实现高效并发所采取的一系列锁优化措施。


1.概述

要点提炼| 理解JVM之内存模型&线程中主要介绍了虚拟机如何实现『并发』,现在的关注点是虚拟机如何实现『高效』。


2.线程安全

在实现高效之前,首先需要保证并发的正确性,因此本节先介绍线程安全。

a.定义:当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。

要求线程安全的代码都必须具备一个特征
代码本身封装了所有必要的正确性保障手段(如互斥同步等),令调用者无须关心多线程的问题,更无须自己采取任何措施来保证多线程的正确调用。

b.分类:按照线程安全的程度由强至弱分成五类

c.线程安全的实现

可分成两大手段,本篇重点在虚拟机本身

  • 通过代码编写实现线程安全
  • 通过虚拟机本身实现同步与锁

互斥同步(Mutual Exclusion&Synchronization)

互斥是因,同步是果;互斥是方法,同步是目的。

非阻塞同步(Non-Blocking Synchronization):

无同步方案

满足可重入性的代码一定是线程安全的,反之,满足线程安全的代码不一定是可重入的。


3.锁优化

解决并发的正确性之后,为了能在线程之间更『高效』地共享数据、解决竞争问题、提高程序的执行效率,下面介绍五种锁优化技术。

a.适应性自旋(Adaptive Spinning)

b.锁消除(Lock Elimination)

c.锁粗化(Lock Coarsening)

一般情况下,会将同步块的作用范围限制到只在共享数据的实际作用域中才进行同步,使得需要同步的操作数量尽可能变小,保证就算存在锁竞争,等待锁的线程也能尽快拿到锁。

但如果反复操作对同一个对象进行加锁和解锁,即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗,此时,虚拟机将会把加锁同步的范围粗化到整个操作序列的外部,这样只需加一次锁。

d.轻量级锁(Lightweight Locking)

首先先理解HotSpot虚拟机的对象头的内存布局:分为两部分

  • 第一部分用于存储对象自身的运行时数据,这部分被称为Mark Word,是实现轻量级锁和偏向锁的关键。如哈希码、GC分代年龄等。
  • 另外一部分用于存储指向方法区对象类型数据的指针,如果是数组对象还会有一个额外的部分用于存储数组长度。

之后虚拟机会尝试用CAS操作将对象的Mark Word更新为指向Lock Record的指针。若更新动作成功,那么当前线程就拥有了该对象的锁,且对象Mark Word的锁标志位变为00,即处于轻量级锁定状态;反之,虚拟机会先检查对象的Mark Word是否指向当前线程的栈帧,若当前线程已有该对象的锁,可直接进入同步块继续执行,否则说明改对象已被其他线程抢占。如下图。

另外,如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁,锁标志位变为10,Mark Word中存储的就是指向重量级锁的指针,后面等待锁的线程也要进入阻塞状态。

e.偏向锁(Biased Locking)

上一篇 下一篇

猜你喜欢

热点阅读