Java多线程系列(六):深入详解Synchronized同步锁的底层实现
谈到多线程就不得不谈到Synchronized,很多同学只会使用,缺不是很明白整个Synchronized的底层实现原理,这也是面试经常被问到的环节,比如:
- synchronized的底层实现原理
- synchronized锁与JVM的实现
- synchronized锁升级顺序
- synchronized锁的优劣势与应用场景
今天主要分享以上内容,详解synchronized的底层实现,多线程相关的可以参考:
Java多线程系列教程:线程的五大状态,以及线程之间的通信与协作
Java多线程系列教程:Java线程池的使用方式,核心运行原理、以及注意事项
最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁
Java多线程系列教程:4种常用Java线程锁的特点,性能比较、使用场景
史上最强多线程面试44题和答案:线程锁+线程池+线程同步等
Synchronized
synchronized 翻译为中文的意思是同步,也称之为”同步锁“。
synchronized的作用是保证在同一时刻, 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果。
Synchronized的使用
1.synchronized的3种使用方式
- 修饰实例方法:作用于当前实例加锁
- 修饰静态方法:作用于当前类对象加锁
- 修饰代码块:指定加锁对象,对给定对象加锁
2.synchronized的代码范例
Synchronized的底层实现
synchronized的底层实现是完全依赖与JVM虚拟机的。
所以谈synchronized的底层实现,就不得不谈数据在JVM内存的存储:Java对象头,以及Monitor对象监视器。
1.Java对象头
在JVM虚拟机中,对象在内存中的存储布局,可以分为三个区域:
- 对象头(Header)
- 实例数据(Instance Data)
- 对齐填充(Padding)
Java对象头主要包括两部分数据:
- 类型指针(Klass Pointer):是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;
- 标记字段(Mark Word):用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等,它是实现轻量级锁和偏向锁的关键.
2.Java锁对象存储位置
所以,很明显synchronized使用的锁对象是存储在Java对象头里的标记字段里。
3.Monitor
synchronized的对象锁,其指针指向的是一个monitor对象(由C++实现)的起始地址。每个对象实例都会有一个 monitor。
Monitor描述为对象监视器,可以类比为一个特殊的房间,这个房间中有一些被保护的数据,Monitor保证每次只能有一个线程能进入这个房间进行访问被保护的数据,进入房间即为持有Monitor,退出房间即为释放Monitor。
使用syncrhoized加锁的同步代码块在字节码引擎中执行时,主要就是通过锁对象的monitor的取用与释放来实现的。
4.线程状态流转在Monitor上体现
描述为对象监视器,当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程:
- Contention List:所有请求锁的线程将被首先放置到该竞争队列
- Entry List:Contention List中那些有资格成为候选人的线程被移到Entry List
- Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set
- OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck
- Owner:获得锁的线程称为Owner
- !Owner:释放锁的线程
下图反映了个状态转换关系
Synchronized 锁的升级顺序
锁解决了数据的安全性,但是同样带来了性能的下降。hotspot 虚拟机的作者经过调查发现,大部分情况下,加锁的代码不仅仅不存在多线程竞争,而且总是由同一个线程多次获得。所以基于这样一个概率。
synchronized 在JDK1.6 之后做了一些优化,为了减少获得锁和释放锁来的性能开销,引入了偏向锁、轻量级锁、自旋锁、重量级锁,锁的状态根据竞争激烈的程度从低到高不断升级。
1.偏向锁
偏向锁是JDK6中引入的一项锁优化,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。
偏向锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。
2.轻量级锁
如果明显存在其它线程申请锁,那么偏向锁将很快升级为轻量级锁。
3.自旋锁
自旋锁原理非常简单,如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。
4.重量级锁
指的是原始的Synchronized的实现,重量级锁的特点:其他线程试图获取锁时,都会被阻塞,只有持有锁的线程释放锁之后才会唤醒这些线程。
偏向锁、轻量级锁、重量级锁优劣势比较
你可能也喜欢:
- Java多线程系列(九):CountDownLatch、Semaphore等4大并发工具类详解
- Java多线程系列(四):4种常用Java线程锁的特点,性能比较、使用场景
- Java多线程系列(一):最全面的Java多线程学习概述
- Java多线程系列(十):源码剖析AQS的实现原理
- Java多线程系列(七):并发容器的原理,7大并发容器详解、及使用场景
- Java多线程系列(八):ConcurrentHashMap的实现原理(JDK1.7和JDK1.8)
Java多线程系列(六):深入详解Synchronized同步锁的底层实现相关推荐
- Java多线程之线程池详解
Java多线程之线程池详解 目录: 线程池使用及优势 线程池3个常用方式 线程池7大参数深入介绍 线程池底层工作原理 1. 线程池使用及优势 线程池做的工作主要是控制运行的线程的数量,处理过程中将任务 ...
- JAVA多线程Thread VS Runnable详解
进程与线程 进程是程序在处理机中的一次运行.一个进程既包括其所要执行的指令,也包括了执行指令所需的系统资源,不同进程所占用的系统资源相对独立.所以进程是重量级的任务,它们之间的通信和转换都需要操作系统 ...
- 【Java 8系列】Stream详解,看这一篇就够啦
热门系列: [Java 8系列]收集器Collector与工具类Collectors [Java 8系列]Lambda 表达式,一看就废 [Java 8系列]Java日期时间的新主宰者:LocalDa ...
- JAVA消息系列:JMS详解
目录 JAVA消息系列-JMS 前言 基本概念 消息模型 P2P模式 Pub/Sub模式 消息的消费 JMS编程模型 JAVA消息系列-JMS 前言 java 消息模块个人理解分为两种: 同步消息(R ...
- iOS多线程系列之GCD栅栏(barrier)实现同步锁
多线程编程中很容易出现资源竞争的问题,比如异步读写操作造成数据不同步.那么解决这一问题多线程编程中提供了一种同步机制叫同步锁.iOS中实现同步锁机制的方案不止一种,这里主要介绍一下强大的GCD给出的方 ...
- 【java】java多线程及线程池详解
目录 前言 线程是什么?多线程是什么? 多线程的作用和好处以及缺点 守护线程和用户线程 并发和并行的区别 一.线程的状态和常用方法 1.线程各种状态转化图 2.线程相关常用方法有 ① wait() ② ...
- 它来了,阿里架构师的“Java多线程+并发编程”知识点详解手册,限时分享
自学Java的时候,多线程和并发这一块可以说是最难掌握的部分了,很多小伙伴表示需要一些易于学习和上手的资料. 所以今天这份「Java并发学习手册」就是一份集中学习多线程和并发的手册,PDF版,由Red ...
- Java多线程中join方法详解
join()方法用于让当前执行线程等待join线程执行结束.其实现原理是不停的检查join线程是否存活,如果join线程存活则让当前线程永远等待. join()方法部分实现细节 while(isAli ...
- Java多线程系列(七):并发容器的原理,7大并发容器详解、及使用场景
之前谈过高并发编程系列: 高并发编程系列:4种常用Java线程锁的特点,性能比较.使用场景 高并发编程系列:CountDownLatch.Semaphore等4大并发工具类详解 高并发编程系列:4大J ...
最新文章
- 合并两个有序数组(重新开始)
- 别人家的团队怎么用RabbitMQ:我总结的5点规范
- [洛谷P4171][JSOI2010]满汉全席
- 从Blue Pill、硬件虚拟化谈安全防护完备性上的一个小原则
- 五 Django 1.5.4 User Authentication 用户认证
- (非原)如何让.net开发的Winform程序快速释放内存
- WinAPI: midiOutClose - 关闭输出设备
- java Hello World程序分析(翻译自Java Tutorials)
- SQLserver通过链接服务器连接oracle
- Java 并发编程实战 -- 常见概念
- matlab在非线性动力学,基于Matlab的非线性动力学系统分析
- Google账号注册失败 无法向手机发验证码
- java 线程 假死_JVM假死问题如何定位?
- np.add.at和np.negative.at
- 接口技术七段数码管c语言,031 实例7-七段数码管绘制
- 搞懂Linux内存屏障(值得收藏)
- 网络篇 谈谈对学习网络的看法
- vs可以开发python吗_vs可以写python吗
- CyberGhost使用、下载、注册【完整教程】
- 如何看产品之:价值链
热门文章
- 网上支付心案例payment
- 18、Linux下编程风格
- #define va_arg(AP, TYPE)
- 要毕业了,我应该做点啥?
- Arm华为NXP睿赛德大咖云集!2020中国嵌入式技术大会嘉宾揭晓
- harmonyos手机开发者beta,HarmonyOS 手机应用开发者 Beta 版到来,对开发者意味着什么...
- 事务嵌套问题_注意Spring事务这一点,避免出现大事务
- c语言如何赋值星期到字母,C语言程序设计课程教案.doc
- 贪吃蛇python小白_面向 python 小白的贪吃蛇游戏
- python导入模块以及类_python—模块导入和类