当前位置: 首页 > 编程日记 > 正文

面试题-自旋锁,以及jvm对synchronized的优化

背景

想要弄清楚这些问题,需要弄清楚其他的很多问题。
比如,对象,而对象本身又可以延伸出很多其他的问题。

我们平时不过只是在使用对象而已,怎么使用?就是new 对象。这只是语法层面的使用,相当于会了一门编程语言而已。

对象更深层次的问题如下:
1.源码实现
2.内存
3.字节码

因为只有了解对象,特别是深刻的理解对象,才能理解同步的问题。

对象

内存
包括三部分
1.头
2.数据
3.空白填充

头是对象的元数据,也就是,除了数据以外的数据。就像各种协议一样,每一种协议,都有头,比如,tcp/ip协议 http协议,都有头字段。
我们这里主要关心的是锁字段。除了锁字段,其实还有,对象的hashcode(唯一标识一个对象),线程等等。

数据,就是数据咯。

空白填充,是一段没有使用的内存。为什么要没有使用的内存,不是浪费吗?因为很多场合,需要申请的内存是什么的倍数,比如,对象需要是8个字节的倍数。所以,内存不够,填充空白字节即可,直到达到8个字节的倍数要求为止。


源码实现
这里也只讲,与同步相关的部分。
比如,c++源码里,与同步关键字synchronized相关的代码是对象监视器ObjectMonitor.cpp。与此相关的逻辑,主要包含以下几个字段:
1.哪个线程拥有这个锁
2.计数器
3.线程排队集合
4.线程等待集合

计数器,情况如下。初始值是0,1.第一次获取,加1 2.如果当前线程再次获取,每次自增1 3.如果是否锁,减1。
同一个线程,再次获取,这就是锁的可重入特性。

线程排队集合,情况如下。1.如果获取到锁,那么持有锁 2.如果没有,那么进入排队集合。

等待集合,情况如下。1.线程获取到锁 2.调用wait()方法,释放锁。加入等待集合。3.等待被别的线程唤醒,即调用notify或notifyAll()方法。


字节码
1.魔数这些东西
2.锁的进入指令enterLock和退出指令exitLock


jvm-如何访问对象


总结
java是由c++实现的。
若要理解java语法是怎么实现的?阅读c++源码,即jvm是如何实现的。

内置锁

内置锁主要包含两个方面
1.哪个锁
2.锁哪个数据


锁的本质
锁,其实就是对象。我们在说哪个锁,其实本质上是在问使用哪个对象。对象就是锁,锁就是对象。每个对象都有一个内置锁,二者一一对应,且互相只有一个。


锁哪个数据?
锁的目的是,要锁住哪个数据。即多线程不能篡改数据。

但是,具体的表现形式是,锁住的是一个代码块。不过,代码块的本质,也是访问数据/操作数据,所以,最终仍然还是为了锁数据。


内置锁的源码实现
1.对象
2.计数


对象
就是锁。


计数 每个对象,关联一个计数器


锁的可重入性
可重入指的是同一个对象/锁,可以重复获取,谁来获取?当然是线程。

获取锁的粒度是线程!只有线程才能获取锁!


锁和要保护的变量之间的关系
一一对应。也就是说,最好保护一个变量就只使用那一个锁来保护那个变量。而不要一个锁同时保护多个变量,那么可能出问题。

显式锁

显式锁和内置锁,本质上是一样的。
只不过,一个是使用关键字(jvm实现了获取锁和释放锁的方法),一个是使用锁封装类的lock()和unlock()方法。

synchronized-源码实现

其实就是上文提到的监视器对象MonitorObject.cpp

jvm对synchronized的优化

1.锁可重入
当前线程可重新获取同一个对象的锁。即同一个锁。
2.自旋锁
自旋锁就是循环获取锁。
锁的源码实现类,封装了lock()和unlock()方法。获取锁的实现,就是循环获取。
3.重量级锁
即普通的对象锁。


一步步是如何优化的,如何进入到下一步
先是锁可重入。这个是针对同一个线程。

其次,如果是不同的线程,那么此刻是自旋锁。即循环指定次数(几十次)的获取锁。

最后,不行,就正常的普通的锁,也就是所谓的重量级锁。该线程进入排队队列。


自旋锁的源码实现
1.普通的锁
获取锁的时候,只获取一次。

2.自旋锁
获取锁的时候,获取多次。

自旋锁和普通锁的唯一区别,就是获取锁的时候,获取几次的问题。


自旋锁的使用
具体使用的时候,自旋锁和普通锁,没有任何区别。所有的显式锁,都是以下两步:
1.获取锁lock()
2.释放锁unlock()

自旋锁,我们自己也可以实现。其实就是一个自旋锁类,封装了两个方法1.获取锁2.释放锁。

synchronized的自旋锁底层实现,也是同一个道理。


代码实现
1.普通锁

lock(){获取锁 //只获取一次,不行,就进入排队队列
}
复制代码

2.自旋锁

lock(){while(次数){获取锁 //获取锁的代码是一样的。主要是修改两个字段1.哪个线程持有锁2.计数器}
}
复制代码

为什么要弄一个自旋锁,因为普通锁,获取一次,获取不到,该线程就进入线程排队队列。再次执行该线程的时候,会发生线程上下文的切换,因为线程进入排队队列的期间,对应的cpu就去执行其他的线程去了。现在又要重新回来执行这个线程,这个过程就发生了至少两次线程上下文切换。而线程上下文切换,是非常耗资源的,具体耗费资源的原因就是,需要在用户态和内核态之间来回切换,线程上下文切换就是由内核来实现上下文切换这个操作的。

互斥锁和非互斥锁

在通常情况下我们说的锁都指的是“互斥”锁,因为在还存在一些特殊的锁,比如“读写锁”,不完全是互斥的。这篇文章说的锁专指互斥锁。


读写锁


读写锁如何实现

延伸-内存溢出和内存泄露的区别:内存泄露是内存溢出的一种

内存问题,说白了,就是不够用的问题。

所以,所有的内存问题,都是因为内存不够用导致的。

内存溢出,就是对象/数据不断地增多。而内存有限。所以,才会溢出嘛。

而内存泄露,其实,本质上,也是内存溢出/不够。只不过有一点细微的区别,就是内存泄露是因为已有的对象,没有做到很好的释放掉。比如,链表里的数据,只释放了第一个数据的内存,后面的数据都没有释放内存。这个时候,会导致剩下的所有数据,都不能被释放。

锁的本质是等待

先理解一下什么是自旋,所谓自旋就是线程在不满足某种条件的情况下,一直循环做某个动作。所以对于自旋锁来锁,当线程在没有获取锁的情况下,一直循环尝试获取锁,直到真正获取锁。

在聊聊高并发(三)锁的一些基本概念 我们提到锁的本质就是等待,那么如何等待呢,有两种方式

  1. 线程阻塞

  2. 线程自旋

阻塞的缺点显而易见,线程一旦进入阻塞(Block),再被唤醒的代价比较高,性能较差。自旋的优点是线程还是Runnable的,只是在执行空代码。当然一直自旋也会白白消耗计算资源,所以常见的做法是先自旋一段时间,还没拿到锁就进入阻塞。JVM在处理synchrized实现时就是采用了这种折中的方案,并提供了调节自旋的参数。


锁的本质是等待,等待的本质是线程阻塞
不管是锁,还是线程阻塞,还是等待。最终落实到源码层面,就是监视器对象MonitorObject的1.线程排队集合2.线程等待集合(即调用了wait()方法)。


Object.wait()方法
Wait方法的本质,也是线程加入到线程等待集合。因为,最底层,jvm还是要调用MonitorObject.cpp的wait()方法,把线程加入到线程等待集合。


线程阻塞的本质是什么?
待补充。


参考
www.jianshu.com/p/f4454164c…
www.jianshu.com/p/3256473f5…
blog.csdn.net/raintungli/…
coderbee.net/index.php/c…

这些参考文章都写的不好,仅供参考。

参考

baijiahao.baidu.com/s?id=161214…

blog.csdn.net/u010372981/…

blog.csdn.net/hellozhxy/a…
blog.csdn.net/iter_zc/art…

www.cnblogs.com/YDDMAX/p/56…

转载于:https://juejin.im/post/5cfddf48e51d455d877e0d04

相关文章:

DNS解析故障

在实际应用过程中可能会遇到DNS解析错误的问题,就是说当我们访问一个域名时无法完成将其解析到IP地址的工作,而直接输入网站IP却可以正常访问,这就是因为DNS解析出现故障造成的。这个现象发生的机率比较大,所以本文将从零起步教给…

cinder存储服务

一、cinder 介绍: 理解 Block Storage 操作系统获得存储空间的方式一般有两种: 1、通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区、格式化、创建文件系统;或者直接使用裸硬盘存储数据&#xff0…

Ubuntu 14.04 64位机上配置Android Studio操作步骤

Android Studio是一个为Android平台开发程序的集成开发环境。2013年5月16日在Google I/O上发布,可供开发者免费使用。Android Studio基于JetBrains IntelliJ IDEA,为Android开发特殊定制,并在Windows、OS X和Linux平台上均可运行。1. 从 htt…

大规模1.4亿中文知识图谱数据,我把它开源了

作者 | Just出品 | AI科技大本营(ID:rgznai100)人工智能从感知阶段逐步进入认知智能的过程中,知识图谱技术将为机器提供认知思维能力和关联分析能力,可以应用于机器人问答系统、内容推荐等系统中。不过要降低知识图谱技术应用的门…

使用CSS 3创建不规则图形

2019独角兽企业重金招聘Python工程师标准>>> 前言 CSS 创建复杂图形的技术即将会被广泛支持,并且应用到实际项目中。本篇文章的目的是为大家开启它的冰山一角。我希望这篇文章能让你对不规则图形有一个初步的了解。 现在,我们已经可以使用CSS…

谷歌丰田联合成果ALBERT了解一下:新轻量版BERT,参数小18倍,性能依旧SOTA

作者 | Less Wright编译 | ronghuaiyang来源 | AI公园(ID:AI_Paradise)【导读】这是来自Google和Toyota的新NLP模型,超越Bert,参数小了18倍。你以前的NLP模型参数效率低下,而且有些过时。祝你有美好的一天。谷歌Resear…

C++中extern C的使用

C程序有时需要调用其它语言编写的函数,最常见的是调用C语言编写的函数。像所有其它名字一样,其它语言中的函数名字也必须在C中进行声明,并且该声明必须指定返回类型和形参列表。对于其它语言编写的函数来说,编译器检查…

Linux之tmpwatch命令

1、tmpwatch命令功能简介[rootvms002 /]# whatis tmpwatch tmpwatch (8) - removes files which havent been accessed for a period of... #删除一段时间内未被访问的文件tmpwatch删除最近一段时间内没有被访问的文件,时间以小时为单位,节省磁盘空间。…

你不得不知道的Visual Studio 2012(1)- 每日必用功能

2019独角兽企业重金招聘Python工程师标准>>> Visual Studio 2012已经正式发布,有很多花哨的新特性,也有很多方便使用者的新功能,当然也有负面声音。对于我们程序员,最关心的还是如何快速掌握VS2012,用于平时…

C++11中std::unique_lock的使用

std::unique_lock为锁管理模板类,是对通用mutex的封装。std::unique_lock对象以独占所有权的方式(unique owership)管理mutex对象的上锁和解锁操作,即在unique_lock对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而unique…

为何Google将几十亿行源代码放在一个仓库?| CSDN博文精选

作者 | Rachel Potvin,Josh Levenberg译者 | 张建军编辑 | apddd【AI科技大本营导读】与大多数开发者的想象不同,Google只有一个代码仓库——全公司使用不同语言编写的超过10亿文件,近百TB源代码都存放在自行开发的版本管理系统Piper中&#…

小小hanoi

为什么80%的码农都做不了架构师?>>> View Code #include " iostream " using namespace std; int k 0 ; void hanoi( int m , char a , char b, char c){ if (m 1 ) { k ; printf( " %c->%c " ,a , c); return…

Unity3D心得分享

本篇文章的内容以各种tips为主,不间断更新 2019/05/10 最近更新: 使用Instantiate初始化参数去实例对象 Unity DEMO学习 Unity3D Adam Demo的学习与研究 Unity3D The Blacksmith Demo部分内容学习 Viking Village维京村落demo中的地面积水效果 Viking V…

django搭建示例-ubantu环境

python3安装--------------------------------------------------------------------------- 最新的django依赖python3,同时ubantu系统默认自带python2与python3,这里单独安装一套python3,并且不影响原来的python环境 django demo使用sqlite3&#xff0c…

C++11中std::lock_guard的使用

互斥类的最重要成员函数是lock()和unlock()。在进入临界区时,执行lock()加锁操作,如果这时已经被其它线程锁住,则当前线程在此排队等待。退出临界区时,执行unlock()解锁操作。更好的办法是采用”资源分配时初始化”(RAII)方法来加…

OpenAI机械手单手轻松解魔方,背靠强化学习+新技术ADR

编译 | 夕颜出品 | AI科技大本营(ID:rgznai100)【导读】10月15日,人工智能研究机构OpenAI发布了一条机械手单手解魔方的视频。这个自学式的类人机器人手臂名为 Dactyl,不仅可以单手解魔方,甚至能在外加各种干扰&#x…

AMD and CMD are dead之js模块化黑魔法

缘由 在2013-03-06 13:58的时候,曾甩下一片文章叫:《为什么不使用requirejs和seajs》,并放下豪言说发布一款完美的模块化库,再后来就把那篇文章删了,再然后就没有然后。该用seajs还用seajs,甚至我码的SCJ都…

一文了解Python常见的序列化操作

关于我 编程界的一名小小程序猿,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。 联系:hylinux1024gmail.com 0x00 marshal marshal使用的是与Python语言相关但与机器无关的二…

TEE(Trusted Execution Environment)简介

TEE(Trusted Execution Environment),可信执行环境,该环境可以保证不被常规操作系统干扰的计算,因此称为”可信”。这是通过创建一个可以在TrustZone的”安全世界”中独立运行的小型操作系统实现的,该操作系统以系统调用(由TrustZ…

自动驾驶关键环节:行人的行为意图建模和预测(上)

作者 | 黄浴出品 | AI科技大本营(ID:rgznai100)【导读】介绍一下最近行人行为意图建模和预测的研究工作,还是分上下两部分,本文为上半部分。Social LSTM: Human Trajectory Prediction in Crowded Spaces比较早的是斯坦福大学 201…

自定义windows下自动清除文件夹或者文件的只读属性的脚本

脚本内容入下:其中脚本中 ”/d"作用 (可以用来改变当前驱动器目录)例如: 我现在是在D盘,现在我要切换到C:\windows目录 脚本参数中 ATTRIB -R /S /D 解释内容如下:(上述脚本参数中的 cd …

C++11容器中新增加的emplace相关函数的使用

C11中,针对顺序容器(如vector、deque、list),新标准引入了三个新成员:emplace_front、emplace和emplace_back,这些操作构造而不是拷贝元素。这些操作分别对应push_front、insert和push_back,允许我们将元素放置在容器头…

Silverlight+WCF 新手实例 象棋 主界面-棋谱-获取列表(三十八)

2019独角兽企业重金招聘Python工程师标准>>> 在线演示地址:SilverlightWCF 新手实例 象棋 在线演示 在SilverlightWCF 新手实例 象棋 主界面-棋谱-布局写谱(三十六)中,我们完成下棋双方的棋谱显示,这节,我们为观众增加…

确认!语音识别大牛Daniel Povey将入职小米,曾遭霍普金斯大学解雇,怒拒Facebook

整理 | 夕颜 出品 | AI科技大本营(ID:rgznai100) 【导读】10 月 17 日,语音界传奇 Daniel Povey 发布推特,宣布自己 2019 年末将要入职小米,目前正在签订合同阶段,入职后,他将带领一支团队研发…

软链接与硬链接

$ ln f1 f2 #创建f1的一个硬连接文件f2$ ln -s f1 f3 #创建f1的一个符号连接文件f3$ ls -li # -i参数显示文件的inode节点信息转载于:https://www.cnblogs.com/zhizouxiao/p/3794668.html

一文读懂Python复杂网络分析库networkx | CSDN博文精选

作者 | yyl424525来源 | CSDN博客文章目录1. 简介安装支持四种图绘制网络图基本流程2. Graph-无向图节点边属性有向图和无向图互转3. DiGraph-有向图一些精美的图例子环形树状图权重图Giant ComponentRandom Geometric Graph 随机几何图节点颜色渐变边的颜色渐变Atlas画个五角星…

C++11多线程中std::call_once的使用

C11中的std::call_once函数位于<mutex>头文件中。在多线程编程中&#xff0c;有时某个任务只需要执行一次&#xff0c;此时可以用C11中的std::call_once函数配合std::once_flag来实现。如果多个线程需要同时调用某个函数&#xff0c;std::call_once可以保证多个线程对该函…

Solaris 上网配置

2019独角兽企业重金招聘Python工程师标准>>> 早上装solaris10系统的时候&#xff0c;没选默认&#xff0c;选了desk-session模式安装。全英文无界面安装&#xff0c;中间还跑出几个乱码。 靠着随便选随便F2&#xff0c;终于安装完了。 就在那设完分辨率后&#xff0…

Configure,Makefile.am, Makefile.in, Makefile文件之间关系

为什么80%的码农都做不了架构师&#xff1f;>>> 1.autoscan (autoconf): 扫描源代码以搜寻普通的可移植性问题&#xff0c;比如检查编译器&#xff0c;库&#xff0c;头文件等&#xff0c;生成文件configure.scan,它是configure.ac的一个雏形。 your source files…

这款耳机一点不输千元级的AirPods

你如果问我&#xff1a;生活中你觉得必不可少的一件电子产品是什么&#xff1f;那么我会毫不犹豫的回答你&#xff1a;是耳机&#xff01;出门忘带耳机是绝对不能忍听不听没关系&#xff0c;但是有它比较安心我觉得生活中不仅是我很多人都对耳机有一种依赖因为很多人都喜欢音乐…