【Java并发编程】线程安全(一)Synchronized原理

Synchronized底层实现

简单来说,Synchronized关键字的执行主体是线程对象,加锁是通过一个锁对象来完成的是,而锁对象底层关联了一个c++源码的monitor的对象,monitor对象底层又对应了操作系统级别的互斥锁,同一时刻只有一个线程能够持有这把锁

Synchronized底层依赖于jvm的monitorenter和monitorexit两个指令,这两个指令用于获取锁和释放锁

请添加图片描述

锁对象结构与sync锁升级的概念

多个线程争抢锁的时候,其实就像是在争抢锁对象,前面提到锁对象底层关联了一个monitor的对象,最终关联操作系统级别的互斥锁,这种情况其实属于申请系统空间的重量级锁,是需要完成系统调用的,因此存在性能问题。

Synchronized自身有一个锁升级的概念:在低并发的情况下先申请用户空间的锁,而不会申请系统空间的锁,也就不涉及用户内核态切换

理解锁升级,首先需要关注Java对象在内存中的存储布局,内部有一个mark-word字段是实现锁升级的关键:

请添加图片描述

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)实例数据(Instance Data)对齐填充(Padding)

对象头内部有一个64bit的mark-word标记字段,后面的三位代表了当前锁对象对应哪种锁:

  • 00:轻量锁
  • 10:重量锁
  • 11:GC标记

(由于2bit不够表示5种锁类型,所以又借了前面一位)

  • 001:无锁
  • 101:轻量级锁

锁升级过程:

  1. 无锁的情况下,第一个线程尝试获得偏向锁:尝试给对象头mark word字段指向的thread id用CAS操作替换成自己的,成功了就直接获得偏向锁
  2. 如果CAS操作失败,意味着同时有多个线程抢锁,这时会在抢到锁的线程到达安全点的时候,将锁升级为轻量级锁,具体操作:拷贝mark word到lock record中,放入到所有抢锁线程的栈中,并且mark word会有指针指向当前占用的锁线程的lock record。其他抢锁的线程利用CAS操作多次自旋,尝试将mark word中的指针指向自己的lock record
  3. 自旋到一定次数升级为重量级锁,抢锁失败的线程进入阻塞状态,这时mark word中的指针将指向对象关联的monitor对象,monitor结构如下:
ObjectMonitor::ObjectMonitor() {  
  _header       = NULL;  
  _count       = 0;  
  _waiters      = 0,  
  _recursions   = 0;       //线程的重入次数
  _object       = NULL;  
  _owner        = NULL;    //标识拥有该monitor的线程
  _WaitSet      = NULL;    //等待线程组成的双向循环链表,_WaitSet是第一个节点
  _WaitSetLock  = 0 ;  
  _Responsible  = NULL ;  
  _succ         = NULL ;  
  _cxq          = NULL ;    //多线程竞争锁进入时的单向链表
  FreeNext      = NULL ;  
  _EntryList    = NULL ;    //_owner从该双向循环链表中唤醒线程结点,_EntryList是第一个节点
  _SpinFreq     = 0 ;  
  _SpinClock    = 0 ;  
  OwnerIsThread = 0 ;  
}

owner属性指向抢锁成功的线程,count记录重入个数。另外还会有入口集entrySet和等待集waitset。

ReentrantLock和Synchronized的选择

这是一个经常被提到的问题

实际上Java发展的过程中对Synchronized的性能做了优化,比如锁升级机制,所以性能上synchronized并不差。

  • 考虑使用ReentrantLock的理由:

主要在一些Synchronized内置锁无法满足需求的情况下,ReentrantLock可以作为一种高级工具

例如,Synchronized具有块结构的特性,即都是在方法/代码块开始是获取,方法/代码块结束时生效。

而ReentrantLock具有非块结构的特性,像下面这种实现就只能使用ReentrantLock

private ReentrantLock lock;

public void foo() {
  ...
  lock.lock();
  ...
}

public void bar() {
  ...
  lock.unlock();
  ...
}

总之,ReentrantLock具备一些高级功能,包括:可定时的、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。否则,还是应该优先使用synchronized。

  • 考虑使用Synchronized的理由:

与ReentrantLock相比,内置锁的一个优点是:能给出在哪些线程调用帧中获得了哪些锁,并能够检测和识别发生死锁的线程。JVM并不知道哪些线程持有ReentrantLock,因此在调试使用ReentrantLock的线程的问题时,将起不到帮助作用。

ReentrantLock的非块结构特性仍然意味着,获取锁的操作不能与特定的栈帧关联起来,而内置锁却可以。

未来更可能会提升synchronized而不是ReentrantLock的性能。因为synchronized是JVM的内置属性,它能执行一些优化,例如对线程封闭的锁对象的锁消除优化,通过增加锁的粒度来消除内置锁的同步,而如果通过基于类库的锁来实现这些功能,则可能性不大。

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

推荐阅读更多精彩内容