线程中并发安全问题(Sychronized关键字的底层原理)

这篇具有很好参考价值的文章主要介绍了线程中并发安全问题(Sychronized关键字的底层原理)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

线程中并发安全问题

Sychronized关键字的底层原理

sychronized对象锁采用互斥方式让同一时刻至多只有一个线程能持有对象锁,其他线程想获取这个对象锁只能被阻塞。

Monitor

Sychronized的底层实现Monitor。
线程中并发安全问题(Sychronized关键字的底层原理),java,redis,开发语言线程中并发安全问题(Sychronized关键字的底层原理),java,redis,开发语言

  • WaitSet:关联调用了wait方法的线程,用于存储处于等待状态的线程。
  • EntryList:关联了没有获得的线程,用于存储处于Blocked状态的线程。
  • Owner:存储当前获取锁的线程,只有一个线程可以获取到(如果Owner为NULL则表示线程可以获取否则就在EntryList中等待,等到当前线程执行完毕,EntryList中的其他线程对锁进行争抢。
Monitor是一个重量级锁(牵扯到一个新的概念:锁升级)

​ monitor实现锁里面涉及到了内核态和用户态的切换,进程的上下文切换成本较高,性能较低。

​ 所以再JDK1.6之后引入了两种新型的锁机制:轻量级锁偏向锁,他们的引入分别解决了同步块中代码不存在竞争,在不同线程交替执行同步代码块中代码不存在竞争这两种因使用传统锁机制产生的性能消耗问题的情况。

所以对象锁是如何关联Monitor的?

对象的内存结构

​ 在HotSpot虚拟机中,对象在内存中存储的分布可分为3个区域:对象头(Header)实例数据(Instance Data),对其填充。

线程中并发安全问题(Sychronized关键字的底层原理),java,redis,开发语言
线程中并发安全问题(Sychronized关键字的底层原理),java,redis,开发语言

MarkWord

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oIHjZVN0-1689425757766)(D:\线程中并发安全问题\QQ截图20230715201033.png)]

  • hashcode:25位的对象标识Hash码
  • age:对象分代年龄占4位
  • biased_lock:偏向锁标识,占1位 ,0表示没有开始偏向锁,1表示开启了偏向锁
  • thread:持有偏向锁的线程ID,占23位
  • epoch:偏向时间戳,占2位
  • ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针,占30位
  • ptr_to_heavyweight_monitor:重量级锁状态下,指向对象监视器Monitor的指针,占30位
Monitor重量级锁

​ 每个对象都可以关联一个Monitor,如果使用sychronized给对象上锁(重量级)后,该对象头中MarkWord中就被修改为指向Monitor对象的指针。

轻量级锁

​ 在很多情况下,Java中的同步代码块并不会被竞争使用,可能会有多个线程交替执行同步块中的代码,这样的情况没必要使用重量级锁,因此Jvm引入了轻量级锁概念。

线程中并发安全问题(Sychronized关键字的底层原理),java,redis,开发语言

​ 当代码执行完成,如果锁记录(Lock Record)为NULL就直接将该锁记录清除,若是不为NULL(也就是原本锁对象CAS过来的MarkWord)此时再进行一次CAS操作将原本的MarkWord交换回来,就代表着解锁成功。

总结

轻量级锁加锁流程:

  • 在线程栈中创建出一条LockRecord锁记录,将其指向锁对象。
  • 通过CAS指令,将LockRecord地址存储到锁对象对象头MarkWord中,若对象处于无锁状态,则修改成功,表示当前线程已经获取到了轻量级锁。
  • 若是当前线程已经持有该锁,代表这是一次锁重入,设置一个新的LockRecard到线程栈中,设置其第一部分为null,起到一个锁重入计数器的功能。
  • 如果CAS修改失败,说明发生了锁竞争,要将其膨胀为重量级锁。

轻量级锁解锁过程:

  • 遍历线程栈找到所有的obj字段(也就是Lock Record地址)为当前锁对象的锁记录。
  • 若是lock record的Markword为null代表着是一次重入,直接清除当前锁记录。
  • 若是不为null则利用cas指令将对象头中的MarkWord交换回来,恢复为无锁状态,若是失败则膨胀为重量级锁。
偏向锁

​ 轻量级锁在没有竞争时,每次重入锁都要进行CAS操作,java6中引入了偏向锁来进一步的优化:只有第一次使用CAS将线程ID设置到对象的MarkWord中,之后每次重入只要发现这个线程ID是自己的就表示没有竞争,不用CAS,以后只要不发生竞争,这个锁对象就归该线程所有。

总结

​ Java中的Sychronized分为偏向锁轻量级锁重量级锁三种形式,分别对应着锁只被一个线程持有不同线程交替持有多线程竞争锁文章来源地址https://www.toymoban.com/news/detail-568262.html

  • 重量级锁:底层使用Monitor实现,里面设计了用户态和内核态的切换,上下文切换,成本高性能低。
  • 轻量级锁:线程的加锁时间是分开的,也就是没有竞争,可以使用轻量级锁来优化,轻量级锁修改对象头的锁标志,相对重量级锁性能提升,每次修改都是CAS保证原子性
  • 偏向锁:一段时间内都是同一个线程持有锁,可以使用偏向锁,在第一次获取锁后,只会一次CAS操作,之后该线程获取锁,只需要判断线程ID是否正确,而不是开销较大的CAS操作。

到了这里,关于线程中并发安全问题(Sychronized关键字的底层原理)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java多线程系列——同步关键字

    目录 一、线程安全和数据不一致性 二、synchronized的作用 三、synchronized工作原理 四、锁的级别 五、synchronized的优点与缺点 六、实战应用 七、总结 在Java中, synchronized 是并发编程中的一个基本构建块,用于控制多个线程对共享资源的访问,以确保数据的一致性

    2024年02月21日
    浏览(42)
  • 多线程系列(四) -volatile关键字使用详解

    在上篇文章中,我们介绍到在多线程环境下,如果编程不当,可能会出现程序运行结果混乱的问题。 出现这个原因主要是,JMM 中主内存和线程工作内存的数据不一致,以及多个线程执行时无序,共同导致的结果。 同时也提到引入 synchronized 同步锁,可以保证线程同步,让多

    2024年02月21日
    浏览(58)
  • 线程中synchronized关键字和lock接口的异同

    一、synchronized 1.可以用来修饰代码块  2.可以用在方法上 修饰同步方法 while (true) { try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(sellTicket()) { break; } } 二、lock接口  1.用此接口要用     ReentrantLock l = new ReentrantLock();     

    2024年02月08日
    浏览(45)
  • Java关键字之synchronized详解【Java多线程必备】

    点击   Mr.绵羊的知识星球  解锁更多优质文章。 目录 一、介绍 二、特性 1. 线程安全 2. 互斥访问 3. 可重入性 4. 内置锁 三、实现原理 四、和其他锁比较 1. 优点 2. 缺点 五、注意事项和最佳实践 六、使用案例 1. 案例一 2. 案例二     synchronized是Java中最基本的同步机制之一,

    2024年01月24日
    浏览(48)
  • 【C语言趣味教程】(7) 存储类:auto 关键字 | register 关键字 | 存储期 | 自动存储期 | 动态存储期 | 线程存储期 | 动态分配存储期 | 静态变量

        🔗 《C语言趣味教程》👈 猛戳订阅!!! 0x00 引入:什么是存储类别? ❓ 你没有听说过 \\\"存储类别\\\" 的概念? 📚 存储类别  (Storage Class) 在 C 语言标准中用来 规定变量与函数的可访问性与生命周期。 \\\"可访问性\\\" 的概念就是我们上一章说的作用域范围,我们先关注以下

    2024年02月10日
    浏览(54)
  • 【JavaEE初阶】多线程(三)volatile wait notify关键字 单例模式

    摄影分享~~ 以上代码运行的结果可能是输入1后,t1这个线程并没有结束。而是一直在while中循环。而t2线程已经执行完了。 以上情况,就叫做 内存可见性问题 这里使用汇编来理解,大概分为两步操作: load,把内存中flag的值,读到寄存器中。 cmp,把寄存器中的值,和0进行比

    2023年04月25日
    浏览(42)
  • 安全初级—正则表达式、This关键字、闭包

    字面量字符 某个字符只表示它字面的含义,例如 /a/ 匹配 a , /b/ 匹配 b 。 元字符 (1)点字符(.) 点字符可以匹配除回车( r )、换行( n )、行分隔符( u2028 )和段分隔符( u2029 )以外的所有字符。 同时,点字符对于码点大于 0xFFFF 字符也不能正确的匹配,会认为这是两个字符

    2024年02月15日
    浏览(44)
  • 【C++】static 关键字的特性 与 问题

    声明为 static的类成员 称为 类的静态成员 用 static 修饰的成员变量 ,称之为 静态成员变量 ; 用 static 修饰的成员函数 ,称之为 静态成员函数 。 静态成员变量 一定要在 类外进行初始化 。 下面一段代码证明 上述定义: 输出结果: 从代码可以看出,静态成员变量需要在 类

    2024年02月14日
    浏览(50)
  • C/C++面试常见问题——const关键字的作用和用法

    首先我们需要一下const的定义, const名叫常量限定符 , 当const修饰变量时,就是在告诉编译器该变量只可访问不可修改,而编译器对于被const修饰的变量有一个优化,编译器不会专门为其开辟空间,而是将变量名和数值作为一个kv键值对存入到符号表中。 注意:const修饰

    2024年02月08日
    浏览(46)
  • scanf和strcpy这类关键字和函数为什么不安全,使用VS编译会报错

    首先先说解决方法: 在程序最顶端加入这个代码段 这主要是微软的 C 运行时库实现将这些函数标记为不安全,主要原因是这些函数缺乏对输入长度的边界检查,容易导致缓冲区溢出漏洞。 会产生这样的报错: 即: C4996    \\\'strcpy\\\': This function or variable may be unsafe. Consider usin

    2024年02月13日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包