标签:入门 原理 访问 监视器 线程之间的通信 使用 唤醒 多个 申请
谈到多线程就不得不谈到Synchronized,很多同学只会使用,缺不是很明白整个Synchronized的底层实现原理,这也是面试经常被问到的环节,比如:
今天主要分享以上内容,详解synchronized的底层实现,多线程相关的可以参考:
Java多线程系列教程:线程的五大状态,以及线程之间的通信与协作
Java多线程系列教程:Java线程池的使用方式,核心运行原理、以及注意事项
最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁
Java多线程系列教程:4种常用Java线程锁的特点,性能比较、使用场景
synchronized 翻译为中文的意思是同步,也称之为”同步锁“。
synchronized的作用是保证在同一时刻, 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果。
1.synchronized的3种使用方式
2.synchronized的代码范例
synchronized的底层实现是完全依赖与JVM虚拟机的。
所以谈synchronized的底层实现,就不得不谈数据在JVM内存的存储:Java对象头,以及Monitor对象监视器。
1.Java对象头
在JVM虚拟机中,对象在内存中的存储布局,可以分为三个区域:
Java对象头主要包括两部分数据:
2.Java锁对象存储位置
所以,很明显synchronized使用的锁对象是存储在Java对象头里的标记字段里。
3.Monitor
synchronized的对象锁,其指针指向的是一个monitor对象(由C++实现)的起始地址。每个对象实例都会有一个 monitor。
Monitor描述为对象监视器,可以类比为一个特殊的房间,这个房间中有一些被保护的数据,Monitor保证每次只能有一个线程能进入这个房间进行访问被保护的数据,进入房间即为持有Monitor,退出房间即为释放Monitor。
使用syncrhoized加锁的同步代码块在字节码引擎中执行时,主要就是通过锁对象的monitor的取用与释放来实现的。
4.线程状态流转在Monitor上体现
描述为对象监视器,当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程:
下图反映了个状态转换关系
锁解决了数据的安全性,但是同样带来了性能的下降。hotspot 虚拟机的作者经过调查发现,大部分情况下,加锁的代码不仅仅不存在多线程竞争,而且总是由同一个线程多次获得。所以基于这样一个概率。
synchronized 在JDK1.6 之后做了一些优化,为了减少获得锁和释放锁来的性能开销,引入了偏向锁、轻量级锁、自旋锁、重量级锁,锁的状态根据竞争激烈的程度从低到高不断升级。
1.偏向锁
偏向锁是JDK6中引入的一项锁优化,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。
偏向锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。
2.轻量级锁
如果明显存在其它线程申请锁,那么偏向锁将很快升级为轻量级锁。
3.自旋锁
自旋锁原理非常简单,如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。
4.重量级锁
指的是原始的Synchronized的实现,重量级锁的特点:其他线程试图获取锁时,都会被阻塞,只有持有锁的线程释放锁之后才会唤醒这些线程。
没钱没人脉也能轻松入门,让你每年多赚10万!
Java多线程系列(六):深入详解Synchronized同步锁的底层实现
标签:入门 原理 访问 监视器 线程之间的通信 使用 唤醒 多个 申请
原文地址:https://www.cnblogs.com/liuyongzhi/p/12848318.html