你所不知道的有关Java 和Scala中的同步问题

原文:Things You Didn’t Know About Synchronization in Java and Scala   译者: 李杰聪

在实际应用中所有的服务端程序都需要在多线程之间进行某种同步。大多数同步已经有框架完成了,比如我们的web服务器,DB客户端和消息框架。Java和Scala提供了大量的组件用来实现稳定的多线程程序。包括对象池,并发集合,高级锁,执行上下文等。

为了更好的理解这些组件,我们深入了解一下最常用的同步原语——对象所。这个是用synchronized 关键字来实现的,在Java中它是非常流行的多线程原语。这也是其他更复杂模式的基础,比如线程池和连接池,并发集合等。

Synchronized 关键字主要用在以下两个场景:

  1. 作为方法的修饰,此方法在同一个时间只能被一个线程执行。
  2. 把一个代码块声明为临界区,任何时间只有一个线程能访问。

锁指令

同步代码块有两个专门的字节码指令,MonitorEnter 和 MoniterExit。这个不同于其它锁机制,比如java.util.concurrent包是有Java代码和本地调用来是实现的。

这些作用在对象上的指令是有开发人员在同步块中显示说明的。对于同步方法,锁被加到了“this”对象上。对于静态方法,锁被加到了类对象上。

同步方法有时候会引起坏的结果。其实一个例子是在不同的同步方法间会引起隐式依赖,因为它们共享同一把锁 。更坏的场景是在基类里(可能是一个第三方库)申明了一个同步方法,在子类里又增加了新的同步方法。这造成了不同层次之间的隐式同步依赖,会降低吞吐率甚至是死循环。这时应该使用私有的锁对象来防止偶然的共享,或者不使用锁。

编译器和同步

有两个字节码的指令用来实现同步原语。这并不常见,因为大多数字节码指令是互相独立的,通常通过把值放在线程的操作数堆栈上来互相“通信”。要加锁的对象也是从操作数堆栈装载的,通过引用变量或者方法返回对象把他们放在操作堆栈上。

如果只有其中一个指令被调用了,而另外一个没被调用,会发生什么?Java编译器不会产生只调用MonitorExit而没有调用MonitorEnter的代码。即使Java编译产生了这样的代码 ,在JVM看来这个代码也是非法的。这会让MonitorExit指令抛出一个IllegalMonitorStateException 异常。

一个更危险的例子是MonitorEnter加了锁,但却没有被对应的MonitorExit释放。这种情况下线程一直拥有锁,从而导致其他想获取这把锁的线程一直被阻塞。

为了防止发生一直被阻塞,Java编译器会以以下方式产生代码:一旦进入同步块或者方法,一定能执行到MonitorExit。在临界区抛出异常可以导致这个问题。

编译器使用的机制非常简单,当异常发生时如果没有经过MonitorExit,就增加catch语句来释放锁。

另一个问题是在enter和exit之间的锁对象存储在何处。注意多个线程可以同时执行同步块,使用不同的锁对象。如果锁对象是方法调用的结果,那么JVM极有可能会再次执行它,因为它可能会改变对象状态,或者不会返回同一个对象。如果是同一个对象,那么在monitor执行前这个变量和域已经被改变。

监视变量。为了计算,编译器为方法增加了一个隐式的变量,用来存储锁状态。这个是一个聪明的解决方案,因为它只增加了很小的开销就维护了锁对象,而不是使用并发栈把锁对象隐射到线程(这个结构需要同步)。我是在编译Takipi栈分析算法时发现这个新变量的。

注意这所有的工作都是有Java的编译器完成的。JVM可以非常完美处理只调用MonitorEnter来进入临界区而不用退出(或者相反),或者为方法使用不同的对象。

JVMLevel的锁

让我们更深入的看一下锁在JVM里是怎么实现的。为此我们将会查看HotSpot SE7的实现,因为这个实现每个VM都可能不一样。 因为加锁会影响代码的吞吐率,JVM加入了很大的优化来提高加锁解锁的效率。

其中一个强大机制是线程锁偏向。锁特性是每个Java对象都具有的,很想系统的hashcode或者定义类的引用。不管类的类型是什么,这个都成立(甚至你可以使用一个原始数组作为锁)。

这些类型的数据都存在对象的头部(也被称为对象的标记)。这些数据中的一部分用来描述对象锁的状态。这包括描述对象的锁状态(加锁/没加锁)的比特标志位,一个指向现在拥有锁的线程。

为了节省对象头部的空间,Java的线程对象会被分配在VM栈的低位,这可以减少地址长度从而节约对象头部的比特数(64位的只需要54位,32位的只需要23位)。

64位的比特位分配情况:

锁算法

当JVM尝试去获取一个对象的锁时,会采用从乐观到悲观的步骤来获取。

当线程成为对象锁的拥有者时,这就算加锁成功了。线程是否把指向自己的引用存入对象的头部决定着加锁是否成功。

获取锁的步骤。第一步是使用CAS操作来尝试获取锁。这个操作非常高效,因为常常有与之对应的CPU指令(比如 cmpxchg)。 CAS操作和OS线程停止程序作为对象的同步原语。

如果锁是空闲或者说这个所可以被这个线程优先获取,那么线程就立即获取了这个锁。如果CAS失败了,那么JVM先会自旋一轮,然后线程会睡眠,直到下次CAS。如果这些最初的尝试失败了,线程会把自己放入阻塞状态,并进入竞争锁的列表,开始一系列的自旋。

释放锁。通过执行MonitorExit指令来退出临界区,锁的拥有者会尝试着检查是否可以唤醒正在等待这把锁的线程 。这个过程被称为选择一个继承者。这可以增加活跃度,阻止出现当锁释放后仍有线程在等待这把锁。

调试服务端多线程问题有点难度,因为它们非常依赖调试时机和OS的特性。这也是让我们实现TAkipi的原因之一。

时间: 2024-10-18 22:25:11

你所不知道的有关Java 和Scala中的同步问题的相关文章

QML中你所不知道的state

QML中你所不知道的state        最后一次写QML已经是2010年了,最近由于产品需要,重拾QML.之前nokia给我们培训QML的时候,对于state这个概念理解的不是很透彻.最近在做产品前期的QML热身,发现QML中的state有一种神奇的功能:历史记忆效应        state核心就是体现了一个状态机的原理,处在某一状态去改变某些属性以达到目的.关于state如何使用的我这里就不说了,看看nokia的QML文档就知道state如何使用.我这里主要讲讲state的历史记忆效应

【干货合集】你所不知道的蚂蚁技术系列之(一):系统设计、性能优化、运维

8月30-31日20:00-21:30,一场别开生面的技术大会-- "蚂蚁金服&阿里云在线金融技术峰会"将在线举办.本次将聚焦数据库.应用架构.移动开发.机器学习等热门领域,帮助金融业技术开发者深入解析互联网应用的前沿应用与技术实践. 蚂蚁金服&阿里云在线金融技术峰会专题:https://yq.aliyun.com/activity/109 峰会统一报名链接:http://yq.aliyun.com/webinar/join/38 2015双11,蚂蚁金服旗下支付宝共完

【javascript杂谈】你所不知道的replace函数

原文:[javascript杂谈]你所不知道的replace函数 前言 最近在做面试题的时候总会用到这个函数,这个函数总是和正则表达式联系到一起,并且效果很是不错,总能很简单出色的完成字符串的实际问题,大家肯定都会使用这个函数,像我一样的初学者可能对这个函数的了解还是不够深的,今天就总结一下,了解一下,再做几道网上的题目练练手,给将要面试的同学打打气. 介绍 使用一个替换值替换掉一个替换模式在原字符串中一个或所有的匹配项,并返回替换后的字符串,这个替换模式可以是字符串或者正则表达式,替换值可以是

你所不知道的关于网管的危险做法

  你所不知道的关于网管的危险做法 网络管理员是指向社会公众开放的营业性上网服务提供场所里的管理员.Jeff Dray 最近经过对IT行业的深入调查研究,通过总结和分析针对IT行业列出了一份类别名单.在这里,他定义了七类最不安全的网络管理员.如果你是一名网络管理员,并且已经意识到工作中还存在着不足,看看你属于名单中的哪一类? 大多数网络管理员对工作游刃有余,并且可以在一个具有高度挑战和技术难度的任务中,使工作顺利进行.然而,有时他们中的某些人会变得很难缠,并会阻碍事情的顺利进行.所以,我定义了一

【干货合集】你所不知道的蚂蚁技术系列之(二):数据、Docker、测试与无线网络技术

8月30-31日20:00-21:30,一场别开生面的技术大会-- "蚂蚁金服&阿里云在线金融技术峰会"将在线举办.本次将聚焦数据库.应用架构.移动开发.机器学习等热门领域,帮助金融业技术开发者深入解析互联网应用的前沿应用与技术实践. 蚂蚁金服&阿里云在线金融技术峰会专题:https://yq.aliyun.com/activity/109 峰会统一报名链接:http://yq.aliyun.com/webinar/join/38 2015双11,蚂蚁金服旗下支付宝共完

【干货合集】你所不知道的蚂蚁技术系列之(三):咻红包、人脸识别、人工智能、金融技术

8月30-31日20:00-21:30,一场别开生面的技术大会-- "蚂蚁金服&阿里云在线金融技术峰会"将在线举办.本次将聚焦数据库.应用架构.移动开发.机器学习等热门领域,帮助金融业技术开发者深入解析互联网应用的前沿应用与技术实践. 蚂蚁金服&阿里云在线金融技术峰会专题:https://yq.aliyun.com/activity/109 峰会统一报名链接:http://yq.aliyun.com/webinar/join/38 2015双11,蚂蚁金服旗下支付宝共完

你所不知道的CSS滤镜技巧与细节

本文主要介绍 CSS 滤镜的不常用用法,希望能给读者带来一些干货! OK,下面直接进入正文.本文所描述的滤镜,指的是 CSS3 出来后的滤镜,不是 IE 系列时代的滤镜,语法如下,还未接触过这个属性的可以先简单到 MDN - filter 了解下: {      filter: blur(5px);      filter: brightness(0.4);      filter: contrast(200%);      filter: drop-shadow(16px 16px 20px 

你所不知道的SQL Server数据库启动过程,以及启动不起来的各种问题的分析及解决技巧

原文:你所不知道的SQL Server数据库启动过程,以及启动不起来的各种问题的分析及解决技巧 目前SQL Server数据库作为微软一款优秀的RDBMS,其本身启动的时候是很少出问题的,我们在平时用的时候,很少关注起启动过程,或者很少了解其底层运行过程,大部分的过程只关注其内部的表.存储过程.视图.函数等一系列应用方式,而当有一天它运行的正常的时候突然启动不起来了,这时候就束手无策了,能做的或许只能是重装.配置.还原等,但这一个过程其实是一个非常耗时的过程,尤其当我们面对是庞大的生产库的时候,

zz疯转:云计算,你所不知道的真相

问题描述 疯转:云计算,你所不知道的真相作者:打死我也得说云计算已经成为不可逆转的产业趋势,云计算概念的火热,不仅让IT人员言必称精通云计算的专家,很多企业的董事长.总经理都亲自过问公司的信息化建设,推动公司转型成云计算的云公司.可是,关于云计算的真相,你真的知道多少?快快了解以下真相,让你成为小伙伴心目中真正的云计算专家吧!否则,千万别给别人说你懂,不然装B代价惨重,nozuonodie啊!(1)云服务商动辄号称99.9%以上的可用性,其实理论上都难以达到国内外云服务提供商几乎都号称自己能提供