synchronize原理

 

synchronized的三种应用方式

一. 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁。

二. 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。

三. 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象。

synchronized的字节码指令

  synchronized同步块使用了monitorenter和monitorexit指令实现同步,这两个指令,本质上都是对一个对象的监视器(monitor)进行获取,这个过程是排他的,也就是说同一时刻只能有一个线程获取到由synchronized所保护对象的监视器。

  线程执行到monitorenter指令时,会尝试获取对象所对应的monitor所有权,也就是尝试获取对象的锁,而执行monitorexit,就是释放monitor的所有权。

synchronized的锁的原理

  两个重要的概念:一个是对象头,另一个是monitor。

Java对象头

  在Hotspot虚拟机中,对象在内存中的布局分为三块区域:对象头(Mark Word、Class Metadata Address)、实例数据和对齐填充;Java对象头是实现synchronized的锁对象的基础。一般而言,synchronized使用的锁对象是存储在Java对象头里。它是轻量级锁和偏向锁的关键。

Mark Word

  Mark Word用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的
锁、偏向线程 ID、偏向时间戳等等。Java对象头一般占有两个机器码(在32位虚拟机中,1个机器码等于4字节,
也就是32bit)。

 

 

Class Metadata Address

  类型指针,即是对象指向它的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

Array length

如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据。

Monitor

  Monitor是一个同步工具,它内置于每一个Object对象中,相当于一个许可证。拿到许可证即可以进行操作,没有拿到则需要阻塞等待。

  在hotspot虚拟机中,通过ObjectMonitor类来实现monitor。

 

 

synchronized锁的优化

  jdk1.6以后对synchronized的锁进行了优化,引入了偏向锁、轻量级锁,锁的级别从低到高逐步升级: 

  无锁->偏向锁->轻量级锁->重量级锁

自旋锁与自适应自旋

  线程的挂起和恢复会极大的影响开销。并且jdk官方人员发现,很多线程在等待锁的时候,在很短的一段时间就获得了锁,所以它们在线程等待的时候,并不需要把线程挂起,而是让他无目的的循环,一般设置10次。这样就避免了线程切换的开销,极大的提升了性能。

而适应性自旋,是赋予了自旋一种学习能力,它并不固定自旋10次一下。他可以根据它前面线程的自旋情况,从而调整它的自旋,甚至是不经过自旋而直接挂起。

锁消除

  对不会存在线程安全的锁进行消除。

锁粗化

  如果jvm检测到有一串零碎的操作都对同一个对象加锁,将会把锁粗化到整个操作外部,如循环体。

偏向锁

  多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让其获得锁的代价更低而引入了偏向锁。

  当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。

  如果测试成功,表示线程已经获得了锁。

  如果测试失败,则需要再测试一下Mark Word中偏向锁的标识是否设置成01(表示当前是偏向锁)。

  如果没有设置,则使用CAS竞争锁。

  如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。

轻量级锁

  引入轻量级锁的主要目的是在多线程竞争不激烈的情况下,通过CAS竞争锁,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

重量级锁

  重量级锁通过对象内部的监视器(monitor)实现,其中monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。

锁升级

  偏向锁升级轻量级锁:当一个对象持有偏向锁,一旦第二个线程访问这个对象,如果产生竞争,偏向锁升级为轻量级锁。

  轻量级锁升级重量级锁:一般两个线程对于同一个锁的操作都会错开,或者说稍微等待一下(自旋),另一个线程就会释放锁。但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁膨胀为重量级锁,重量级锁使除了拥有锁的线程以外的线程都阻塞,防止CPU空转。

wait和notify的原理

  调用wait方法,首先会获取监视器锁,获得成功以后,会让当前线程进入等待状态进入等待队列并且释放锁。

  当其他线程调用notify后,会选择从等待队列中唤醒任意一个线程,而执行完notify方法以后,并不会立马唤醒线程,原因是当前的线程仍然持有这把锁,处于等待状态的线程无法获得锁。必须要等到当前的线程执行完按monitorexit指令以后,也就是锁被释放以后,处于等待队列中的线程就可以开始竞争锁了。

wait和notify为什么需要在synchronized里面?

  wait方法的语义有两个,一个是释放当前的对象锁、另一个是使得当前线程进入阻塞队列,而这些操作都和监视器是相关的,所以wait必须要获得一个监视器锁。

而对于notify来说也是一样,它是唤醒一个线程,既然要去唤醒,首先得知道它在哪里,所以就必须要找到这个对象获取到这个对象的锁,然后到这个对象的等待队列中去唤醒一个线程。

转载于:https://www.cnblogs.com/heqiyoujing/p/11144649.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247634.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不能修改“System Roots”钥匙串

iOS mac添加证书 不能修改“System Roots”钥匙串错误 如图: 解决方式: 打开钥匙串---登录---,直接把证书拖过来 然后,查看--我的证书,里面,找到证书,即可

未来产品的设计

Donald A. Norman继《情感化设计》之后,又一设计精品力作: 未来产品的设计样章试读及本书预定:http://www.china-pub.com/195642市场价 :¥39.00 会员价 : ¥29.25(75折) 【作  者】(美)Donald…

css之字体图标

SVG与字体图标 SVG图片是矢量图片,不会随着图片的伸缩而影响质量,通常把只有一种颜色的图标做成SVG,通过SVG生成字体图标,放到项目中使用。 https://icomoon.io/是一个比较快捷的生成字体图标的线上工具,进入主页后&…

研发阶段模拟接口数据

因为在vue-cli工程中需要创建很多.vue文件,我们希望创建vue文件和创建html、css、js文件一样右键即可选择创建,并且创建的文件中可预先写好模板代码。 webstorm-Preferences打开选项界面 选择File and Code Templates,点击绿色加号 填…

真实项目中 ThreadLocal 的妙用

一、什么是 ThreadLocal ThreadLocal 提供了线程的局部变量,每个线程都可以通过 set() 和 get() 来对这个局部变量进行操作,但不会和其他线程的局部变量冲突,实现了线程间的据隔离。 简单讲:一个获取用户的请求线程 A,…

css之flex布局

flex布局是css3中的重要布局方式,称为“弹性布局”,每次想到它主要是遇到元素垂直居中、元素宽高自适应的问题,这些问题在flex中都能过简单设置就解决,它更像是原生APP中的布局操作,布局不必写N多的盒模型代码来实现&a…

javascript对URL中的参数进行简单加密处理

javascript的api本来就支持Base64,因此我们可以很方便的来进行编码和解码。 var encodeData window.btoa("namexiaoming&age10")//编码 var decodeData window.atob(encodeData)//解码。 下面来个具体的例子来说明如何对url中参数进行转码&#xff…

HTML元素title里面如何换行

在调试代码的时候我就遇到一个问题,HTML元素title里面通常只显示一行,那我想要他换行,就是多行显示,如何实现?JS代码里面比如Alert里面又该如何换行? 经过我的一番实验 要实现这种效果有几种方法&#xff0…

div内图片和文字水平垂直居中

大小不固定的图片、多行文字的水平垂直居中 本文综述 想必写css的都知道如何让单行文字在高度固定的容器内垂直居中,但是您知道或者想过让行数不固定的文字在高度固定的容器内垂直居中呢?本文将会告诉你如何实现多行文字的垂直居中显示。 关于图片垂直居…

敏友的【敏捷个人】有感(3): 有感于“敏捷个人”讨论与练习

2010年我对个人管理进行了自己的一些思考,在2011年提出敏捷个人概念,并且在线上、线下进行了多次交流,在一些大会上也做过分享。现在,已经有很 多IT和非IT的敏友们知道并在践行敏捷个人,帮助自己更快的成长。我收到大家…

jQuery编写插件

引言: 在项目中不同页面经常要用到已经写好的交互,比如弹窗,比如下拉菜单,比如选项卡,比如删除... 此时如果每次都把代码copy一份无疑是一件比较麻烦并且无趣的事情,而且个人认为有些low了,我们…

webstorm中nodejs代码提示

preferences->languages&frameworks->Node.js and Npm中选择一个本地的node版本 preferences->languages&frameworks->JavaScript->Libraries 勾选node.js Core 回到代码

Array.prototype.slice.call(arguments)

Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组,除了IE下的节点集合(因为ie下的dom对象是以com对象的形式实现的,js对象与com对象不能进行转换)如:1 var a{length:2,0:first,1:second}; 2 Ar…

nodejs常用模块-url

URL nodejs中针对url的常用方法。 node下打印url,结果: 引入url模块 var url require(url) 1、parse方法 将url解析成对象,parse方法原型: url.parse(urlStr[, parseQueryString][, slashesDenoteHost]) 可传递三个参数…

常用的javascript设计模式

请坚持 什么是设计模式 百度百科: 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式…

iOS警告-This block declaration is not a prototype

关于警告 我们定义一个不带参数的block,通常是如下的方式 1typedefvoid (^UpdateSwichBtnBlock)();在xcode9中会提示一个警告 12This block declaration is not a prototypeInsert ‘void解决方式可以是如下的几种 1typedefvoid (^UpdateSwichBtnBlock)(void);但是这样,很多第三…

mongoose操作mongodb

http://mongoosejs.com/docs/api.html#index-js mongoose是nodejs环境下操作mongodb的模块封装,使用mongoose之后,实际上只需要在mongodb中创建好数据库与用户,集合的定义、创建、操作等直接使用mongoose即可。 一、连接二、重要概念三、基本…

mac下iterm配色、半透明与样式设置

主要为了实现命令行颜色高亮与整个命令窗口半透明效果。 1、配色主题包下载 1、http://iterm2colorschemes.com/ 下载后解压,到iterm2中,左上角iTerm2->preferences->Profiles,右侧面板找到Colors选项,右下角展开Color Pr…

一个 Dubbo 服务启动要两个小时

前几天在测试环境碰到一个非常奇怪的与 dubbo 相关的问题,事后我在网上搜索了一圈并没有发现类似的帖子或文章,于是便有了这篇。 希望对还未碰到或正在碰到的朋友有所帮助。 现象 现象是这样的,有一天测试在测试环境重新部署一个 dubbo 应用的…

表单提交enctype参数详解之:application/x-www-form-urlencode和multipart/form-data

application/x-www-form-urlencode 我们在提交表单的时候,form表单参数中会有一个enctype的参数。enctype指定了HTTP请求的Content-Type。 默认情况下,HTML的form表单的enctypeapplication/x-www-form-urlencoded。 application/x-www-form-urlencoded是…