线程三

锁原理

通过openJDK 开发的jar包-JOL去分析Java对象头信息

首先Java对象有三部分组成 1:对象头,2:对象的实例数据,3:对齐字节padding

对象的实例数据:对象中的字段数据

对齐字节(padding)

对象头:每个gc管理的堆对象开头的公共结构(每个oop都指向一个对象标头)包括堆对象的布局、类型、GC状态、同步状态和标识哈希码的基本信息,

由两个词组成(mark word,klass word)。64位系统为例,一共占128bit  16byte,开启指针压缩时占12byte(klass word 有关)。

klass word

klass word为对象头的第二个词,主要指向对象的元数据,也可以说是指向类元数据的指针。元数据可以理解为Class对象模板

开启指针压缩的时候占4byte(32bit),不开启占8byte(64bit)

mark word

mark word为第一个word根据文档可以知他里面包含了锁的信息,hashcode,gc信息等等 总长度64位(bit) 8byte,

对象不同状态(锁的各种状态,GC标记)时,对象头中每个位的数据也不同。详见下表

|———————————————————————————————————————————————————————————————————————————————————————————————————————————————|

|       Object header     |

| ——————————————————————————————————————————————————————————————————————————————————————————————————————————————|

|状态  | mark word 8Byte   |    klass word      |

|——————|———————————————————————————————————————————————————————————————————————————————|————————————————————————|

|无锁  |unused:25 | identity_hashCode:31 | unused 1 | age:4 | biased_lock:1 | lock:2  |  OOP to metadata object|

|——————|———————————————————————————————————————————————————————————————————————————————|————————————————————————|

|偏向锁|thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:2  |  OOP to metadata object|

|——————|———————————————————————————————————————————————————————————————————————————————|————————————————————————|

|轻量锁|                ptr_to_lock_record:62     | lock:2  |  OOP to metadata object| 

|——————|———————————————————————————————————————————————————————————————————————————————|————————————————————————|       

|重量锁|                ptr_to_heavyweight_monitor 62     | lock:2  |  OOP to metadata object|

|——————|———————————————————————————————————————————————————————————————————————————————|————————————————————————| 

|GC标识|     | lock:2  |  OOP to metadata object|

|——————————————————————————————————————————————————————————————————————————————————————|—————————————————————————

文字解读上表mark word信息:

对象状态无锁状态时,前0-24位未使用,25-55位hashcod,56位未使用,57-60位对象GC状态年龄代标识,61位偏向锁标记, 62-63锁状态,

对象状态偏向锁时,前0-53位为线程标记,54-55位为 epoch,56位未使用,57-60位对象GC状态年龄代标识,61位偏向锁标记,62-63锁状态,

对象状态轻量级锁时,0-61位为指针 ptr指针,指向lock的record指针,62-63锁状态

对象状态为重量级锁时,0-61位为xxx ptr指针,指向monitor对象的指针,62-63锁状态

对象状态被GC标识时 0-61为空,

通过将第61、62、63三个位的数值组合,便可以标识五种对象状态即 000:轻量级,001:无锁,101:偏向锁,010:重量级锁,空+11:GC标记

epoch:类似的机制称为批量再偏置(bulk rebiasing),它可以优化这样的情况:一个类的对象被不同的线程锁定和解锁,但是不会并发。

它在不禁用偏向锁定的情况下使类的所有实例的偏向无效。类中的epoch值充当表示偏差有效性的时间戳。此值将在对象分配时复制到标题字中。

然后,可以有效地在适当的类中以历元增量的形式实现批量再偏。下一次这个类的实例被锁定时,代码将检测到一个不同的

只有调用了对象的hashCode后,对象头信息mark word 词中才会有hashCode的信息,否则mark word中将不会有hashCode信息,通过JOL去打

印类的布局,可以查看到对象头信息再调用了hashCode方法后的变化。小端存储模型下,对象的hashCode高位对应mark word中存储hashCode

值得低位。比如,对象调用了hashCode方法后,hashCode值十六进制下为198e2867,前文提到mark word 中前56位为hashCode ,小段存储模式下,

后56位对应hashCode得值,即:00000001 01100111(67) 00101000(28) 10001110(8e) 00011001(19) 00000000 00000000 00000000

运行一下代码:

package com.test;

import org.openjdk.jol.info.ClassLayout;

import static java.lang.System.out;

public class JOLExample2 {

//Thread.sleep(5000);

static A a;

public static void main(String[] args) throws Exception {

//Thread.sleep(5000);

a = new A();

out.println("befre lock");

out.println(ClassLayout.parseInstance(a).toPrintable());

sync();

out.println("after lock");

out.println(ClassLayout.parseInstance(a).toPrintable());

}

public static void sync() throws InterruptedException {

synchronized (a){

System.out.println("我也不知道要打印什么");

}

}

}

理应输出的时偏向锁,然后通过JOL打印出来的却是轻量级锁,如果打开注释的Thread.sleep(5000);则运行结果会打印此对象状态位偏向锁,这是因为

JVM在启动时做的偏向锁延迟导致的。可以通过JVM参数 :-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0禁止延迟偏向锁。

为什么要用偏向锁延迟,JVM启动时,某个类有一个线程访问,那么它为偏向锁,当第二个线程来访问的时候,会锁消除升级为轻量级锁,这个过程

是相当发杂且耗费资源的,JVM可以确定虚拟机启动时大部分为轻量级锁,所以JDK做了优化,等JVM启动完成后,在加载偏向锁,不用进行锁消除 升级操作

轻量级锁和偏向锁的性能对比,差距十分之大,偏向锁的性能高,轻量级锁性能低。 十倍左右的差距

调用wait()方法后立即升级为重量级锁

释放锁跟修改对象头mark word中锁状态的值不是一个东西,释放锁是释放锁,改对象头信息是改对象头信息,不一样。同步代码块执行完都会释放锁,并不一定会

改变对象状态的标志位

偏向锁在退出同步代码块后锁依然保持偏向信息,当一个轻量/重量级锁在退出代码块后会将锁状态会消除还原为一个无锁状态,因为锁的膨胀过程。

为什么在没有同步之前对象也是偏向锁?

轻量级锁是什么时候发生的:线程交替执行无竞争

同步{

1.单线程

2.多个线程交替执行 一般为轻量级锁,当发生互斥的时候,第二个线程会自旋,等待一个时间(有资料说为一个线程上下文切换的时间),

    如果在自选时间内获取到了锁,依然为轻量级锁,获取不到升级为重量级锁。自旋锁

3.多个线程互斥执行  一般为重量级锁

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容