网上有许多讲偏向锁,轻量级锁的文章,但对偏向锁如何升级讲的不够明白,有些文章还相互矛盾,经过对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;
              }
          }

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

  1. Java并发之锁升级:无锁->偏向锁->轻量级锁->重量级锁

    Java并发之锁升级:无锁->偏向锁->轻量级锁->重量级锁 对象头markword 在lock_bits为01的大前提下,只有当是否偏向锁位值为1的时候,才表明当前对象处于偏向锁定 ...

  2. java 偏向锁怎么升级为轻量级锁

    因为偏向锁,锁住对象时,会写入对象头相应的标识,我们先把对象头(官方叫法为:Mark Word)的图示如下(借用了网友的图片): 通过上面的图片,我们可以知道,对象处于偏向锁时,mark word中的 ...

  3. MySQL 避免行锁升级为表锁——使用高效的索引

    文章目录 普通索引 属性值重复率高 属性值重复率低 小结 众所周知,MySQL 的 InnoDB 存储引擎支持事务,支持行级锁(innodb的行锁是通过给索引项加锁实现的).得益于这些特性,数据库支持 ...

  4. 每个java初学者都应该搞懂的问题

    对于这个系列里的问题,每个学JAVA的人都应该搞懂.当然,如果只是学JAVA玩玩就无所谓了.如果你认为自己已经超越初学者了,却不很懂这些问题,请将你自己重归初学者行列.内容均来自于CSDN的经典老贴. ...

  5. 五分钟学Java:一篇文章搞懂spring和springMVC

    原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 本文思维导图 什么是Spring,为什么你要学习spring? 你第一次接触spring框架是在什么时候?相信很多人和我一样,第一次了 ...

  6. Java Builder 模式,你搞懂了么?

    加油.png 前言:最近闲来无事的时候想着看看一些平常用的三方库源码,没想到看了之后才知道直接撸源码好伤身体,一般设计优秀的开源库都会涉及很多的设计模式,就比如 android 开发使用频繁的 okH ...

  7. Java基础-一文搞懂位运算

    在日常的Java开发中,位运算使用的不多,使用的更多的是算数运算(+.-.*./.%).关系运算(<.>.<=.>=.==.!=)和逻辑运算(&&.||.!), ...

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

    1        安装JDK=> (1,下载JDK,安装,一般目录为C:\Program Files\Java中:2,通过Dos命令测试JDK是否安装=>java –version命令查看 ...

  9. 线程池 | Java多线程,彻底搞懂线程池

    熟悉Java多线程编程的同学都知道,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了. 最近看了一些相关文章,并亲自研究了一下源码,发现有些文章还是有些问题的,所以我也总结了 ...

随机推荐

  1. thinkphp问题

    这几天组里有个php系统报安全漏洞,负责的厂商跑了,没办法,被组长丢过来改漏洞,记录一下部分内容. 配置php的环境  参考https://blog.csdn.net/u011415782/artic ...

  2. MyEclipse中Ctrl+Shift+F快捷键格式化代码时不换行

    摘自: http://iteye.blog.163.com/blog/static/18630809620121166622410/ MyEclipse中Ctrl+Shift+F快捷键格式化代码时不换 ...

  3. poj 1260 Pearls 斜率优化dp

    这个题目数据量很小,但是满足斜率优化的条件,可以用斜率优化dp来做. 要注意的地方,0也是一个决策点. #include <iostream> #include <cstdio> ...

  4. [Node.js] Level 6. Socket.io

    6.2 Setting Up socket.io Server-Side So far we've created an Express server. Now we want to start bu ...

  5. Verilog 基础回顾 (一)

    Verilog 大小写敏感,且所有关键字都是小写 1  寄存器 register = storage,是数据存储单元的抽象,可视为能够存储数值的变量 (variable that can hold v ...

  6. (队列的应用5.3.3)POJ 3125 Printer Queue(优先队列的使用)

    /* * POJ_3125.cpp * * Created on: 2013年10月31日 * Author: Administrator */ #include <iostream> # ...

  7. vb 获取打印机名称

    Const HKLM = &H80000002 '定义根键常数 '其他常用根键 Const HKCR = &H80000000 , Const HKCU = &H8000000 ...

  8. Eddy&#39;s digital Roots

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission ...

  9. UNIX环境编程初步认识——编程环境搭建

     前言 前期学习了Linux的一些基本知识后,在借助前期的学习的基础上想再初步认识一下操作系统的一些环境编程体系相关知识,当中环境的配置和搭建费了非常大的劲,须要一点点摸索和尝试,下边是环境搭建的 ...

  10. 【Oracle】表空间相关集合

    创建表空间 1.语法 CREATE [SMALLFILE/BIGFILE] TABLESPACE tablespace_nameDATAFILE '/path/filename' SIZE num[k ...