热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

帮你深入了解synchronized关键字

帮你深入了解synchronized关键字学习这些锁之前先来了解一下MarkWord。什么是重量锁?什么是轻量锁?什么是偏向锁?这几种状态

帮你深入了解synchronized关键字

    • 学习这些锁之前先来了解一下MarkWord。
    • 什么是重量锁?
    • 什么是轻量锁?
    • 什么是偏向锁?
    • 这几种状态怎么流转?


学习这些锁之前先来了解一下MarkWord。

整个对象头在32位操作系统下的内存分配
由此可见java的设计者们,真的是把mark-word设计到了极限。都是为了省内存啊。
内容都在图里。就不多赘述了。

什么是重量锁?

这个我觉得人人都应该清楚,其实java以前如果要解决线程安全问题。就要依赖于操作系统帮忙生成monitor监视器对象。你就认为是“锁”,由监视器对象来协调线程安全问题。
之所以叫 重量锁 就是因为如果使用这种方式,就要依赖于操作系统帮忙。会涉及到内核态和用户态的转换。(这块如果不理解可以百度哦)
java代码:

public class SyncDemo {private Integer i = 0;public void test(){synchronized (this){i++;}}
}

编译后的字节码:

public void test();Code:0: aload_01: dup2: astore_13: monitorenter // 这里向操作系统申请锁4: aload_05: getfield #3 // Field i:Ljava/lang/Integer;8: astore_29: aload_010: aload_011: getfield #3 // Field i:Ljava/lang/Integer;14: invokevirtual #4 // Method java/lang/Integer.intValue:()I17: iconst_118: iadd19: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;22: dup_x123: putfield #3 // Field i:Ljava/lang/Integer;26: astore_327: aload_228: pop29: aload_130: monitorexit // 释放锁31: goto 4134: astore 436: aload_137: monitorexit // 异常失败也释放锁38: aload 440: athrow41: returnException table:from to target type4 31 34 any34 38 34 any

其实重量锁,就是new 了一个monitor对象,

  1. 加锁时把对象(syn关键字锁的对象)的mark-word copy到monitor对象中,并将30bit保存为指向monitor的ref引用指针
  2. 解锁时复原回mark-word

什么是轻量锁?

上面说到,重量锁性能比较差,毕竟代码是要时时刻刻执行的。那么这群java设计者就想,我能不能在java用户态层面就把锁这个东西给控制住了。不需要使用那么重的监视器。
所以他们设计出了轻量锁,可以类比上面加锁解锁过程。

只不过加锁解锁通过CAS 操作mark-word对象头。因为CAS操作是非常小并发代价。

CAS过程

  • 加锁线程将对象(syn关键字锁的对象)的mark-word copy到本线程的栈帧中。
  • 将原mark-word中的30bit 内容保存成指向栈帧的ref引用地址
  • 解锁时同样,只要将栈帧中的copy-mark-word复原会对象头。

CAS 操作会有成功和失败。成功即表示加锁成功,失败即表示加锁失败。此时升级重量锁。
思考:

  1. 什么时候会失败?
  2. 如果一个线程已经加过轻量锁,但是被另一个线程申请成了重量锁。它CAS复原mark-word解锁时会怎么办?

什么是偏向锁?

因为轻量锁,毕竟还是要每次都CAS,虽然CAS性能非常高。但这群“疯子”想还能不能优化。不要每次都CAS。而且轻量锁还涉及mark-word的copy,势必也会影响到GC。
但程序中很多场景,虽然要保证线程安全,但是80%的时间都不会有资源竞争。

此时偏向锁闪亮登场:
即当第一个线程来加锁时,通过一次CAS操作,将自己的threadId保存进markword中。只要成功就代表加锁成功。以后该线程再来加锁时,只要对比一下自己的threadId和markword中的threadId是不是一样就可以了。偏向 偏向 意思就是这个锁已经偏向给第一个线程了。

是不是一直用偏向锁呢,什么时候会被打破?
肯定不是啊,那不然还要轻量和重量锁啥用。当第二个线程来加锁时(不管第一个线程是否解锁),就宣告锁对象的偏向模式结束。就被升级为轻量或者重量。

这几种状态怎么流转?

前面说了很多都是文字。下面我通过一张图来描述一下整个流程怎么转换:
在这里插入图片描述

附上《深入理解jvm虚拟机》中的流程转换:
在这里插入图片描述


推荐阅读
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • MPLS VP恩 后门链路shamlink实验及配置步骤
    本文介绍了MPLS VP恩 后门链路shamlink的实验步骤及配置过程,包括拓扑、CE1、PE1、P1、P2、PE2和CE2的配置。详细讲解了shamlink实验的目的和操作步骤,帮助读者理解和实践该技术。 ... [详细]
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文由编程笔记小编整理,主要介绍了使用Junit和黄瓜进行自动化测试中步骤缺失的问题。文章首先介绍了使用cucumber和Junit创建Runner类的代码,然后详细说明了黄瓜功能中的步骤和Steps类的实现。本文对于需要使用Junit和黄瓜进行自动化测试的开发者具有一定的参考价值。摘要长度:187字。 ... [详细]
  • 本文介绍了如何在Mac上使用Pillow库加载不同于默认字体和大小的字体,并提供了一个简单的示例代码。通过该示例,读者可以了解如何在Python中使用Pillow库来写入不同字体的文本。同时,本文也解决了在Mac上使用Pillow库加载字体时可能遇到的问题。读者可以根据本文提供的示例代码,轻松实现在Mac上使用Pillow库加载不同字体的功能。 ... [详细]
author-avatar
x-诗儿_683
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有