Java并发之彻底搞懂偏向锁升级为轻量级锁

网上有许多讲偏向锁,轻量级锁的文章,但对偏向锁如何升级讲的不够明白,有些文章还相互矛盾,经过对jvm源码(biasedLocking.cpp)的仔细分析和追踪,基本升级过程有了一个清晰的过程,现将升级流程阐述如下:

因为偏向锁,锁住对象时,会写入对象头相应的标识,我们先把对象头(官方叫法为:Mark Word)的图示如下(借用了网友的图片):

通过上面的图片,我们可以知道,对象处于偏向锁时,mark word中的偏向锁标记为1,锁标志位为01;下面是分析过jvm源码(biasedLocking.cpp)解析的偏向锁升级流程(忽略一些细节),示例中:线程1当前拥有偏向锁对象,线程2是需要竞争到偏向锁。

  1. 线程2来竞争锁对象;
  2. 判断当前对象头是否是偏向锁;
  3. 判断拥有偏向锁的线程1是否还存在;
  4. 线程1不存在,直接设置偏向锁标识为0(线程1执行完毕后,不会主动去释放偏向锁);
  5. 使用cas替换偏向锁线程ID为线程2,锁不升级,仍为偏向锁;
  6. 线程1仍然存在,暂停线程1;
  7. 设置锁标志位为00(变为轻量级锁),偏向锁为0;
  8. 从线程1的空闲monitor record中读取一条,放至线程1的当前monitor record中;
  9. 更新mark word,将mark word指向线程1中monitor record的指针;
  10. 继续执行线程1的代码;
  11. 锁升级为轻量级锁;
  12. 线程2自旋来获取锁对象;

上面仍有一个问题,即如何判断线程1已经不存在了?

仍然是分析完jvm源码(thread.cpp)后,得到的如下结论:

(1) 线程执行start时,会将自己写入一个thread_list中,这是一个linked结构,有pre和next节点;

对应源码位置:

void Threads::add(JavaThread* p, bool force_daemon) {

// The threads lock must be owned at this point

assert_locked_or_safepoint(Threads_lock);

// See the comment for this method in thread.hpp for its purpose and

// why it is called here.

p->initialize_queues();

p->set_next(_thread_list);

_thread_list = p;

_number_of_threads++;

oop threadObj = p->threadObj();

bool daemon = true;

// Bootstrapping problem: threadObj can be null for initial

// JavaThread (or for threads attached via JNI)

if ((!force_daemon) && (threadObj == NULL || !java_lang_Thread::is_daemon(threadObj))) {

_number_of_non_daemon_threads++;

daemon = false;

}

p->set_safepoint_visible(true);

ThreadService::add_thread(p, daemon);

// Possible GC point.
  Events::log(p, "Thread added: " INTPTR_FORMAT, p);

}

(2)线程执行完后,会将自己从thread list中清理掉(源码位置: Threads::remove(this));

因此只需判断thread list中是否存在线程1即可,判断源代码(位于biasedLocking.cpp中 )如下:

bool thread_is_alive = false;

if (requesting_thread == biased_thread) {

thread_is_alive = true;

} else {

     for (JavaThread* cur_thread = Threads::first(); cur_thread != NULL; cur_thread = cur_thread->next()) {

if (cur_thread == biased_thread) {

thread_is_alive = true;

break;

}

}

原文地址:https://www.cnblogs.com/tiancai/p/9382542.html

时间: 2024-10-19 14:05:09

Java并发之彻底搞懂偏向锁升级为轻量级锁的相关文章

虚拟机中的锁优化简介(适应性自旋/锁粗化/锁削除/轻量级锁/偏向锁)

高效并发是JDK 1.6的一个重要主题,HotSpot虚拟机开发团队在这个版本上花费了大量的精力去实现各种锁优化技术,如适应性自旋(Adaptive Spinning).锁削除(Lock Elimination).锁膨胀(Lock Coarsening).轻量级锁(Lightweight Locking).偏向锁(Biased Locking)等,这些技术都是为了在线程之间更高效地共享数据,以及解决竞争问题,从而提高程序的执行效率. 13.3.1 自旋锁与自适应自旋 前面我们讨论互斥同步的时候,

JAVA初级必须要搞懂的事项(希望对新手有所帮助)

1        安装JDK=> (1,下载JDK,安装,一般目录为C:\Program Files\Java中:2,通过Dos命令测试JDK是否安装=>java –version命令查看安装JDK版本:3.更改环境变量(1,设置变量名:JAVA_HOME.设置变量值为D:jdk6.0;新建PATH,设置变量值为%JAVA_HOME%bin; class_path,变量值为.;C:\Program Files\Java\jdk1.6.0_43\lib\dt.jar;):4,通过javac命令显

Java基础-一文搞懂位运算

在日常的Java开发中,位运算使用的不多,使用的更多的是算数运算(+.-.*./.%).关系运算(<.>.<=.>=.==.!=)和逻辑运算(&&.||.!),所以相对来说对位运算不是那么熟悉,本文将以Java的位运算来详细介绍下位运算及其应用. 1. 位运算起源 位运算起源于C语言的低级操作,Java的设计初衷是嵌入到电视机顶盒内,所以这种低级操作方式被保留下来.所谓的低级操作,是因为位运算的操作对象是二进制位,但是这种低级操作对计算机而言是非常简单直接,友好高效

Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

Java并发编程系列[未完]: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) 一.重量级锁 上篇文章中向大家介绍了Synchronized的用法及其实现的原理.现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的.而操作系统实现线程之间的切换这就需要从用户态转换到核心

java 中的锁 -- 偏向锁、轻量级锁、重量级锁

理解锁的基础知识 如果想要透彻的理解java锁的来龙去脉,需要先了解以下基础知识. 基础知识之一:锁的类型 锁从宏观上分类,分为悲观锁与乐观锁. 乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作. java中的乐观锁基本都是通过CAS操作实现的,CAS

Java锁---偏向锁、轻量级锁、自旋锁、重量级锁

之前做过一个测试,反复执行过多次,发现结果是一样的: 1. 单线程下synchronized效率最高(当时感觉它的效率应该是最差才对): 2. AtomicInteger效率最不稳定,不同并发情况下表现不一样:短时间低并发下,效率比synchronized高,有时甚至比LongAdder还高出一点,但是高并发下,性能还不如synchronized,不同情况下性能表现很不稳定: 3. LongAdder性能稳定,在各种并发情况下表现都不错,整体表现最好,短时间的低并发下比AtomicInteger

java 偏向锁、轻量级锁及重量级锁synchronized原理

Java对象头与Monitor java对象头是实现synchronized的锁对象的基础,synchronized使用的锁对象是存储在Java对象头里的. 对象头包含两部分:Mark Word 和 Class Metadata Address 其中Mark Word在默认情况下存储着对象的HashCode.分代年龄.锁标记位等以下是32位JVM的Mark Word默认存储结构 由于对象头的信息是与对象自身定义的数据没有关系的额外存储成本,因此考虑到JVM的空间效率,Mark Word 被设计成

一句话撸完重量级锁、自旋锁、轻量级锁、偏向锁、悲观、乐观锁等

重量级锁?自旋锁?自适应自旋锁?轻量级锁?偏向锁?悲观锁?乐观锁?执行一个方法咋这么辛苦,到处都是锁. 今天这篇文章,给大家普及下这些锁究竟是啥,他们的由来,他们之间有啥关系,有啥区别. 重量级锁 如果你学过多线程,那么你肯定知道锁这个东西,至于为什么需要锁,我就不给你普及了,就当做你是已经懂的了. 我们知道,我们要进入一个同步.线程安全的方法时,是需要先获得这个方法的锁的,退出这个方法时,则会释放锁.如果获取不到这个锁的话,意味着有别的线程在执行这个方法,这时我们就会马上进入阻塞的状态,等待那

Synchronized锁性能优化偏向锁轻量级锁升级 多线程中篇(五)

不止一次的提到过,synchronized是Java内置的机制,是JVM层面的,而Lock则是接口,是JDK层面的 尽管最初synchronized的性能效率比较差,但是随着版本的升级,synchronized已经变得原来越强大了 这也是为什么官方建议使用synchronized的原因 毕竟,他是一个关键字啊,这才是亲儿子,Lock,终归差了一点 简单看下,synchronized大致都经过了哪些重要的变革 重量级锁 对于最原始的synchronized关键字,锁被称之为重量级锁 因为底层依赖监