scala和java像不像_关于Java和Scala同步的五件事你不知道

scala和java像不像

实际上,所有服务器应用程序都需要在多个线程之间进行某种同步。 大多数同步工作是在框架级别为我们完成的,例如通过我们的Web服务器,数据库客户端或消息传递框架。 Java和Scala提供了许多组件来编写可靠的多线程应用程序。 这些包括对象池,并发集合,高级锁,执行上下文等。 blog_trampoline

为了更好地理解它们,让我们探索最同步的习惯用法-Object lock 。 这种机制为synced关键字提供了动力,使其成为Java中最流行的多线程习惯用法之一(如果不是)。 它也是我们使用的许多更复杂的模式的基础,例如线程和连接池,并发集合等等。

synced关键字在两个主要上下文中使用:

  1. 作为方法修饰符,用于标记一种方法,该方法一次只能由一个线程执行。
  2. 通过将代码块声明为关键部分 –在任何给定时间点仅一个线程可以使用一个代码块。

锁定说明

事实1 。 同步代码块使用两条专用字节码指令实现,这是官方规范的一部分-MonitorEnterMonitorExit 。 这与其他锁定机制(例如在java.util.concurrent包中找到的锁定机制)不同,该锁定机制是结合Java代码和通过sun.misc.Unsafe进行的本机调用来实现的(对于HotSpot而言)。

这些指令对开发人员在同步块的上下文中明确指定的对象进行操作。 对于同步方法,锁定将自动选择为“ this ”变量。 对于静态方法,锁将放置在Class对象上。

同步方法有时会导致不良行为 。 一个示例是在相同对象的不同同步方法之间创建隐式依赖关系,因为它们共享相同的锁。 更糟糕的情况是在基类(甚至可能是第3方类)中声明同步方法,然后将新的同步方法添加到派生类。 这会在整个层次结构中创建隐式同步依赖关系,并有可能导致吞吐量问题甚至死锁。 为避免这些情况,建议使用私有对象作为锁,以防止意外共享或逃脱锁。

编译器和同步

有两个字节码指令负责同步。 这是不寻常的,因为大多数字节码指令彼此独立,通常通过将值放在线程的操作数堆栈上来彼此“通信”。 还可以从操作数堆栈中加载要锁定的对象,该操作数堆栈先前是通过取消引用变量,字段或调用返回对象的方法来放置的。

事实#2。 那么,如果调用这两个指令之一而没有分别调用另一个指令会发生什么呢? 如果不调用MonitorEnter,Java编译器将不会生成调用MonitorExit的代码。 即使这样,从JVM的角度来看,这样的代码也是完全有效的。 这种情况的结果是MonitorExit指令抛出IllegalMonitorStateException。

如果通过MonitorEnter获得锁但没有通过对MonitorExit的相应调用释放锁,将会发生更危险的情况 。 在这种情况下,拥有该锁的线程可能导致其他试图获取该锁的线程无限期地阻塞。 值得注意的是,由于该锁是可重入的,因此拥有该锁的线程可能会继续愉快地执行,即使它再次到达并重新输入相同的锁也是如此。

这就是陷阱。 为了防止这种情况的发生,Java编译器以这样的方式生成匹配的输入和退出指令:一旦执行已进入同步块或方法,它就必须通过匹配的MonitorExit指令来处理同一对象。 可能会引起麻烦的一件事是,如果在关键部分内引发了异常。

public void hello() {synchronized (this) {System.out.println("Hi!, I'm alone here");}
}

让我们分析一下字节码–

aload_0 //load this into the operand stack
dup //load it again
astore_1 //backup this into an implicit variable stored at register 1
monitorenter //pop the value of this from the stack to enter the monitor//the actual critical section
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "Hi!, I'm alone here"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)Vaload_1 //load the backup of this
monitorexit //pop up the var and exit the monitor
goto 14 // completed - jump to the end// the added catch clause - we got here if an exception was thrown -
aload_1 // load the backup var.
monitorexit //exit the monitor
athrow // rethrow the exception object, loaded into the operand stack
return

编译器用来防止栈不展开而无需通过MonitorExit指令的机制非常简单–编译器添加了一个隐式的try…catch子句以释放锁并重新抛出异常。

事实三 。 另一个问题是在相应的enter和exit调用之间存储的对锁定对象的引用在哪里。 请记住,多个线程可能会使用不同的锁对象同时执行同一同步块。 如果锁定的对象是调用方法的结果,则JVM极不可能再次执行它,因为它可能会更改对象的状态,甚至可能不会返回相同的对象。 对于自输入监视器以来可能已更改的变量或字段,情况也是如此。

监视变量 。 为了解决这个问题,编译器将一个隐式局部变量添加到方法中,以保存锁定对象的值。 这是一个明智的解决方案,因为与使用并发堆结构将锁定对象映射到线程(该结构本身可能需要同步)相比,该方法在维护对锁定对象的引用上的开销很小。 在构建Takipi的堆栈分析算法时,我首先观察到了这个新变量,并发现代码中弹出了意外变量。

注意,所有这些工作都是在Java编译器级别完成的。 JVM非常乐意通过MonitorEnter指令进入关键部分而不退出(反之亦然),或将不同的对象用作对应的enter和exit方法。

锁定在JVM级别

现在让我们更深入地研究如何在JVM级别上实际实现锁。 为此,我们将检查HotSpot SE 7的实现,因为这是VM特定的。 由于锁定可能会对代码吞吐量产生非常不利的影响,因此JVM进行了一些非常强大的优化,以尽可能高效地获取和释放锁定。

事实#4。 JVM所采用的最强大的机制之一是线程锁偏置 。 锁定是每个Java对象都具有的固有功能,就像具有系统哈希码或对其定义类的引用一样。 无论对象的类型如何,都是如此(如果您愿意,甚至可以使用基本数组作为锁)。

这些类型的数据存储在每个对象的标头(也称为对象的标记)中。 保留在对象标题中的某些数据保留用于描述对象的锁定状态。 这包括描述对象的锁定状态(即锁定/解锁)的位标志,以及对当前拥有该锁的线程的引用-指向该对象的线程有偏。

为了节省对象标头中的空间,为了减小地址大小并节省每个对象标头中的位(64位和32位JVM为54位或23位),在VM堆的较低段中分配了Java线程对象。分别)。

对于64位–

blog_normal-object

锁定算法

当JVM尝试获取对象的锁时,它会经历从乐观到悲观的一系列步骤。

事实五。 如果线程成功将其自身确立为对象锁的所有者,则该线程将获取该锁。 这取决于线程是否能够在对象的标头中安装对自身的引用(指向内部JavaThread对象的指针)。

获取锁。 使用简单的比较和交换(CAS)操作即可完成此操作。 这非常有效,因为它通常可以转换为直接CPU指令(例如cmpxchg)。 CAS操作以及OS特定的线程驻留例程用作对象同步习惯用法的构建块。

如果该锁是免费的,或者先前已对该线程进行了锁定,则将获得该线程的对象锁,并且可以立即继续执行。 如果CAS失败,则JVM将执行一轮自旋锁定,在该循环中线程停放以有效地使其在重试CAS之间进入睡眠状态。 如果这些初始尝试失败(向锁发出更高级别的争用信号),线程将自身进入阻塞状态,并使其自身进入争用该锁的线程列表,并开始一系列自旋锁。

在每轮旋转之后,线程将检查JVM全局状态的变化,例如“停止世界” GC的出现,在这种情况下,线程将需要暂停自身直到GC完成以防止出现这种情况。在执行STW GC时获得锁并继续执行的位置。

释放锁。 通过MonitorExit指令退出关键部分时,所有者线程将尝试查看它是否可以唤醒任何正在等待释放锁的驻留线程。 此过程称为选择“继承人”。 这是为了增加活动性,并防止在释放锁(也称为绞合)的情况下保持线程停放的情况。

调试服务器多线程问题很困难,因为它们往往取决于非常特定的时间安排和操作系统启发。 这就是让我们首先从事Takipi工作的原因之一。

参考:我们的JCG合作伙伴 Tal Weiss在Takipi博客上对Java和Scala中的同步不了解的5件事 。

翻译自: https://www.javacodegeeks.com/2013/08/5-things-you-didnt-know-about-synchronization-in-java-and-scala.html

scala和java像不像

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

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

相关文章

BPSK调制下(2,1,6)标准卷积码及打孔生成2/3、3/4、4/5、5/6删余码Viterbi译码误码率曲线图(MATLAB实现)

关注公号【逆向通信猿】更精彩!!! 目录 仿真结果卷积码原理图删余后性能比较常用的删余码仿真代码根据码率生成打孔参数(子函数)将标准(2, 1, 6)编码后的序列进行打孔,生成删余码(子函数)对接收到的序列进行反打孔,将原来打孔删除的比特进行补零(子函数)BPSK调制下(2,1,6…

江南大学物联网工程学院数据库课程实验三作业3vb.net实验报告

一、开发环境 语言环境:Microsoft.NET Framework 4.6 SDK IDE:Microsoft Visual Studio Community 2015 二、代码及配置 1、Form1 Public Class Form1Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.LoadEnd SubPrivate …

[2021.07.25更新]循环冗余校验(CRC)的MATLAB实现

欢迎同步关注公众号【逆向通信猿】 CRC校验(循环冗余校验) 在计算CRC校验的时候,发现一个网站如下 http://www.ip33.com/crc.html 于是,想自己动手实现该网站计算CRC校验的功能,网站提供的在线计算工具是以十六进制来表示输入参数和结果的,为了方便MATLAB实现,本文提供…

江南大学物联网工程学院数据库课程实验四作业4vb.net实验报告

一、开发环境 语言环境:Microsoft.NET Framework 4.6 SDK IDE:Microsoft Visual Studio Community 2015 二、代码 Imports System.Data.SqlClient Public Class Form1 连接本机数据库并获取test_one数据库中的sc表数据 Dim mybind As BindingManagerB…

MATLAB库函数hilbert(希尔伯特变换)的C语言实现(FFT采用FFTW库)

目录希尔伯特变换原理公式MATLAB官方帮助文档中希尔伯特变换算法常量和结构体定义C语言实现(FFTW库的float版,double版类似)希尔伯特变换原理公式 MATLAB官方帮助文档中希尔伯特变换算法 hilbert uses a four-step algorithm: Calculate the FFT of the input sequ…

netbeans7.4_NetBeans 7.4 Beta提示警告无效的异常处理

netbeans7.4有许多例子说明Java异常处理可能比首次出现时要困难得多,Josh Bloch专门将一整章的《 Effective Java》 (两个版本)专门用于异常处理。 Java中的检查异常模型 仍然 “ 有争议” 。 我很高兴看到我最近下载的NetBeans 7.4 beta有一…

在厚度仅十几微米的电池隔膜找缺陷?人工智能说,能行(人工智能应用案例)

原文链接:https://www.paddlepaddle.org.cn/support/news?actiondetail&id2104 “我们的质检要做的是在厚度仅十几微米的电池隔膜上找出所有微小缺陷,如果没有检测出来,就很可能使新能源汽车的电池在使用过程中出现问题,甚至…

准确率超90%、1秒发出报警,人工智能助国网山东实现无人巡检(人工智能应用案例)

原文链接:https://mp.weixin.qq.com/s/Jh2YLY-4um79ucdHIs5NTg 众所周知,深度学习框架是人工智能的基础技术“底座”,在各大传统产业上也有着巨大的潜力尚待挖掘。5月20日,由深度学习技术及应用国家工程实验室与百度联合主办的“…

基于PaddlePaddle实现高尔夫球场的遥感检测(人工智能应用案例)

原文链接:https://www.paddlepaddle.org.cn/support/news?actiondetail&id2103 1 . 背景及意义 随着高尔夫球运动在我国的兴起,关于高尔夫球场大量占用土地资源、污染环境、耗水量大且公益性差的争议越来越多。国家从2004年开始制定一系列相关政策…

MATLAB库函数firls(最小二乘线性相位FIR滤波器设计)的C语言实现

firls函数功能 FILS设计了一种线性相位FIR滤波器,它可以最小化理想分段线性函数与滤波器在一组期望频带上的幅值响应之间的加权积分平方误差。 b = firls(n,f,a) b = firls(n,f,a,w) b = firls(n,f,a,ftype) b = firls(n,f,a,w,ftype)f是在0和1之间的范围内指定的频率点对的…

数电实验一-初识Multisim和Basys3

特别说明:该系列内容均是本人实验记录,无盗取侵权之嫌,仅供参考,请多动手实践! 一、实验目的 详见报告 二、实验仪器设备 详见报告 三、实验设计过程 使用Multisim为Basys3板卡创建一个PLD设计并进行验证。 1.创建P…

自动化学科前沿讲座作业 基于深度学习的工厂人员监测系统设计

1 背景及应用场景 在工业复杂生产环境下,作业人员的安全问题至关重要。大多数工业企业采用人眼观察视频的方式对作业人员位置进行判断,这种方式长时间会使管理者出现疲劳问题,效率非常低下,遇到安全问题也不能进行及时的处理。采用…

多重继承java_Java中的多重继承与组合vs继承

多重继承java有时我写了几篇有关Java 继承 , 接口和组成的文章。 在这篇文章中,我们将研究多重继承,然后了解组成优于继承的好处。 Java中的多重继承 多重继承是创建具有多个超类的单个类的能力。 与其他一些流行的面向对象的编程语言&#…

数电实验二-点亮一个数码管(Multisim和Basys3 )

特别说明:该系列内容均是本人实验记录,无盗取侵权之嫌,仅供参考,请多动手实践。 一、实验目的 详见报告 二、实验环境 详见报告 三、实验内容 (1)基本要求:以Basys3四位拨码开关SW3~SW0为输入…

倍福(Beckhoff)嵌入式控制器PLC

前些天发现了十分不错的人工智能学习网站,通俗易懂,风趣幽默,没有广告,分享给大家,大家可以自行看看。(点击跳转人工智能学习资料) 摘要:与家喻户晓的西门子相比,倍福&am…

fftw-3.3.8库在linux下的的编译和配置

关注公号【逆向通信猿】更精彩!!! 运行环境 Ubuntu 14.04版本以上,64位系统 FFTW库的下载 首先在官网上下载fftw-3.3.8.tar.gz压缩包,解压。本人下载好的压缩包地址:https://download.csdn.net/download/wlwdecs_dn/12904577 FFTW库的生成 首先,将压缩包进行解压,…

Spring Security with Spring Boot 2.0:密码编码器

在上一篇文章中,我们使用了用户详细信息服务,以便提供一种基于给定用户名从函数加载数据的方法。 用户详细信息的实现可能由内存机制,sql / no-sql数据库等支持。 选项是无限的。 关于密码存储,我们必须注意的是密码哈希。 出…

循环自相关函数和谱相关密度(三)——实信号、复信号模型下的BPSK信号循环谱MATLAB仿真结果及代码

关注公号【逆向通信猿】,循环谱 说明:接上一节循环自相关函数和谱相关密度(二)——实信号、复信号模型下的BPSK信号循环谱推导 7.5 仿真结果 7.5.1 实BPSK信号 符号速率RB = 40,采样率Fs = 960,载波频率fc = 300,符号数N = 1000,矩形成形。

executor线程池框架_如何使用Java 5 Executor框架创建线程池

executor线程池框架Java 5以Executor框架的形式在Java中引入了线程池,它允许Java程序员将任务提交与任务执行分离。 如果要使用Java进行服务器端编程,则线程池是维护系统可伸缩性,鲁棒性和稳定性的重要概念。 对于那些不熟悉Java中的线程池或…

JavaFX技巧29:使布局忽略不可见的节点

在我仍在Swing中实现UI的时候,我曾经是MigLayout的忠实拥护者(“一个布局管理者来统治所有这些,对吗Mikael?”)。 我真正喜欢的功能之一是当组件不可见时可以定义不同的行为。 MigLayout允许我保留现在不可见的组件所占…