synchronized
是 Java 编程中的一个重要的关键字,也是多线程编程中不可或缺的一员。本文就对它的使用和锁的一些重要概念进行分析。
synchronized 是一个重量级锁,它主要实现同步操作,在 Java 对象锁中有三种使用方式:
在代码中使用方法分别如下:
普通方法使用:
/**
* 公众号:ytao
* 博客:https://ytao.top
*/
public class SynchronizedMethodDemo{
public synchronized void demo(){
// ......
}
}
静态方法使用:
/**
* 公众号:ytao
* 博客:https://ytao.top
*/
public class SynchronizedMethodDemo{
public synchronized static void staticDemo(){
// ......
}
}
代码块中使用:
/**
* 公众号:ytao
* 博客:https://ytao.top
*/
public class SynchronizedDemo{
public void demo(){
synchronized (SynchronizedDemo.class){
// ......
}
}
}
方法和代码块的实现原理使用不同方式:
每个对象都拥有一个monitor
对象,代码块的{}
中会插入monitorenter
和monitorexit
指令。当执行monitorenter
指令时,会进入monitor
对象获取锁,当执行monitorexit
命令时,会退出monitor
对象释放锁。同一时刻,只能有一个线程进入在monitorenter
中。
先将SynchronizedDemo.java
使用javac SynchronizedDemo.java
命令将其编译成SynchronizedDemo.class
。然后使用javap -c SynchronizedDemo.class
反编译字节码。
Compiled from "SynchronizedDemo.java"
public class SynchronizedDemo {
public SynchronizedDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void demo();
Code:
0: ldc #2 // class SynchronizedDemo
2: dup
3: astore_1
4: monitorenter // 进入 monitor
5: aload_1
6: monitorexit // 退出 monitor
7: goto 15
10: astore_2
11: aload_1
12: monitorexit // 退出 monitor
13: aload_2
14: athrow
15: return
Exception table:
from to target type
5 7 10 any
10 13 10 any
}
上面反编码后的代码,有两个monitorexit
指令,一个插入在异常位置,一个插入在方法结束位置。
方法中的synchronized
与代码块中实现的方式不同,方法中会添加一个叫ACC_SYNCHRONIZED
的标志,当调用方法时,首先会检查是否有ACC_SYNCHRONIZED
标志,如果存在,则获取monitor
对象,调用monitorenter
和monitorexit
指令。
通过javap -v -c SynchronizedMethodDemo.class
命令反编译SynchronizedMethodDemo
类。-v
参数即-verbose
,表示输出反编译的附加信息。下面以反编译普通方法为例。
Classfile /E:/SynchronizedMethodDemo.class
Last modified 2020-6-28; size 381 bytes
MD5 checksum 55ca2bbd9b6939bbd515c3ad9e59d10c
Compiled from "SynchronizedMethodDemo.java"
public class SynchronizedMethodDemo
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #5.#13 // java/lang/Object."<init>":()V
#2 = Fieldref #14.#15 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Methodref #16.#17 // java/io/PrintStream.println:()V
#4 = Class #18 // SynchronizedMethodDemo
#5 = Class #19 // java/lang/Object
#6 = Utf8 <init>
#7 = Utf8 ()V
#8 = Utf8 Code
#9 = Utf8 LineNumberTable
#10 = Utf8 demo
#11 = Utf8 SourceFile
#12 = Utf8 SynchronizedMethodDemo.java
#13 = NameAndType #6:#7 // "<init>":()V
#14 = Class #20 // java/lang/System
#15 = NameAndType #21:#22 // out:Ljava/io/PrintStream;
#16 = Class #23 // java/io/PrintStream
#17 = NameAndType #24:#7 // println:()V
#18 = Utf8 SynchronizedMethodDemo
#19 = Utf8 java/lang/Object
#20 = Utf8 java/lang/System
#21 = Utf8 out
#22 = Utf8 Ljava/io/PrintStream;
#23 = Utf8 java/io/PrintStream
#24 = Utf8 println
{
public SynchronizedMethodDemo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 5: 0
public synchronized void demo();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED // ACC_SYNCHRONIZED 标志
Code:
stack=1, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: invokevirtual #3 // Method java/io/PrintStream.println:()V
6: return
LineNumberTable:
line 8: 0
line 10: 6
}
SourceFile: "SynchronizedMethodDemo.java"
上面对代码块和方法的实现方式进行探究:
monitorenter
和monitorexit
指令。ACC_SYNCHRONIZED
标志,来决定是否调用monitor
对象。synchronized
锁的相关数据存放在 Java 对象头中。Java 对象头指的 HotSpot 虚拟机的对象头,使用2个字宽或3个字宽存储对象头。
Mark Word
。Java 对象头 Mark Word 存储内容:
存储内容 | 标志位 | 状态 |
---|---|---|
对象的hashCode、GC分代年龄 | 01 | 无锁 |
指向栈中锁记录的指针 | 00 | 轻量级锁 |
指向重量级锁的指针 | 10 | 重量级锁 |
空 | 11 | GC标记 |
线程ID、Epoch(一个时间戳)、GC分代年龄 | 01 | 偏向锁 |
synchronized 称为重量级锁,但 Java SE 1.6 为优化该锁的性能而减少获取和释放锁的性能消耗,引入偏向锁
和轻量级锁
。
锁的高低级别为:无锁
→偏向锁
→轻量级锁
→重量级锁
。
其中锁的升级是不可逆的,只能由低往高级别升,不能由高往低降。
偏向锁是优化在无多线程竞争情况下,提高程序的的运行性能而使用到的锁。在Mark Word
中存储一个值,用来标志是否为偏向锁,在 32 位虚拟机和 64 位虚拟机中都是使用一个字节存储,0 为非偏向锁,1 为是偏向锁。
当第一次被线程获取偏向锁时,会将Mark Word
中的偏向锁标志设置为 1,同时使用 CAS 操作来记录这个线程的ID。获取到偏向锁的线程,再次进入获取锁时,只需判断Mark Word
是否存储着当前线程ID,如果是,则不需再次进行获取锁操作,而是直接持有该锁。
如果有其他线程出现,尝试获取偏向锁,让偏向锁处于竞争状态,那么当前偏向锁就会撤销。撤销偏向锁时,首先会暂停持有偏向锁的线程,并将线程ID设为空,然后检查该线程是否存活:
当确定代码一定执行在多线程访问中时,那么这时的偏向锁是无法发挥到优势,如果继续使用偏向锁就显得过于累赘,给系统带来不必要的性能开销,此时可以设置 JVM 参数-XX:BiasedLocking=false
来关闭偏向锁。
代码进入同步块的时候,如果对象头不是锁定状态,JVM 则会在当前线程的栈桢中创建一个锁记录
的空间,将锁对象头的Mark Word
复制一份到锁记录
中,这份复制过来的Mark Word
叫做Displaced Mark Word
。然后使用 CAS 操作将锁对象头中的Mark Word
更新为指向锁记录
的指针。如果更新成功,当前线程则会获得锁,如果失败,JVM 先检查锁对象的Mark Word
是否指向当前线程,是指向当前线程的话,则当前线程已持有锁,否则存在多线程竞争,当前线程会通过自旋获取锁,这里的自旋可以理解为循环尝试获取锁,所以这过程是消耗 CPU 的过程。当轻量级锁存在竞争状态并自旋获取轻量级锁失败时,轻量级锁就会膨胀为重量级锁,锁对象的Mark Word
会更新为指向重量级锁的指针,等待获取锁的线程进入阻塞状态。
轻量级锁解锁是使用 CAS 操作将锁记录
替换到Mark Word
中,如果替换成功,则表示同步操作已完成。如果失败,则表示其他竞争线程尝试过获取该轻量级锁,需要在释放锁的同时,去唤醒其他被阻塞的线程,被唤醒的线程回去再次去竞争锁。
通过分析
synchronized
的使用以及 Java SE 1.6 升级优化锁后的设计,可以看出其主要是解决是通过多加入两级相对更轻巧的偏向锁和轻量级锁来优化重量级锁的性能消耗,但是这并不是一定会起到优化作用,主要是解决大多数情况下不存在多线程竞争以及同一线程多次获取锁的的优化,这也是根据平时在编码中多观察多反思得出的权衡方案。
本文由哈喽比特于4年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/KpJZFLTeCxiuxQeiyEEJpQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。