首页 > 其他分享 >Synchronized的底层实现原理(看这篇就够了)

Synchronized的底层实现原理(看这篇就够了)

时间:2022-08-30 15:34:56浏览次数:73  
标签:加锁 Synchronized synchronized 对象 这篇 线程 偏向 底层

谈到多线程就不得不谈到Synchronized,重要性不言而喻,今天主要分享Synchronized的底层实现。

 

Synchronized

synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized 翻译为中文的意思是同步,也称之为”同步锁“。

synchronized的作用是保证在同一时刻, 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果。

Synchronized的使用方式

主要有3种使用方式:

1.修饰实例方法:作用于当前实例加锁

public synchronized void method(){
// 代码
}

2.修饰静态方法:作用于当前类对象加锁

public static synchronized void method(){
// 代码
}

3.修饰代码块:指定加锁对象,对给定对象加锁

synchronized(this){
//代码

}

Synchronized的底层实现

synchronized的底层实现是完全依赖JVM虚拟机的,所以谈synchronized的底层实现,就不得不谈数据在JVM内存的存储:Java对象头,以及Monitor对象监视器。

1.Java对象头

在JVM虚拟机中,对象在内存中的存储布局,可以分为三个区域:

  • 对象头(Header)
  • 实例数据(Instance Data)
  • 对齐填充(Padding)

Java对象头主要包括两部分数据:

 

1)类型指针(Klass Pointer)

是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;

2)标记字段(Mark Word)

用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等,它是实现轻量级锁和偏向锁的关键.

所以,很明显synchronized使用的锁对象是存储在Java对象头里的标记字段里。

2.Monitor

monitor描述为对象监视器,可以类比为一个特殊的房间,这个房间中有一些被保护的数据,monitor保证每次只能有一个线程能进入这个房间进行访问被保护的数据,进入房间即为持有monitor,退出房间即为释放monitor。

下图是synchronized同步代码块反编译后的截图,可以很清楚的看见monitor的调用。

在这里插入图片描述

使用syncrhoized加锁的同步代码块在字节码引擎中执行时,主要就是通过锁对象的monitor的取用(monitorenter)与释放(monitorexit)来实现的。

当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程:

Contention List:所有请求锁的线程将被首先放置到该竞争队列
Entry List:Contention List中那些有资格成为候选人的线程被移到Entry List
Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set
OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck
Owner:获得锁的线程称为Owner
!Owner:释放锁的线程

下图反映了个状态转换关系:

 

Synchronized 的锁升级

锁解决了数据的安全性,但是同样带来了性能的下降,hotspot 虚拟机的作者经过调查发现,大部分情况下,加锁的代码不仅仅不存在多线程竞争,而且总是由同一个线程多次获得。

所以基于这样一个概率,synchronized 在JDK1.6 之后做了一些优化,为了减少获得锁和释放锁来的性能开销,引入了偏向锁、轻量级锁,锁的状态根据竞争激烈的程度从低到高不断升级。

1.无锁

无锁没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。

2.偏向锁

偏向锁是JDK6中引入的一项锁优化,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

偏向锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。

3.轻量级锁

是指当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。

4.重量级锁

指的是原始的Synchronized的实现,重量级锁的特点:其他线程试图获取锁时,都会被阻塞,只有持有锁的线程释放锁之后才会唤醒这些线程。

 

标签:加锁,Synchronized,synchronized,对象,这篇,线程,偏向,底层
From: https://www.cnblogs.com/wffzk/p/16639472.html

相关文章

  • synchronized 原理
    java中每一个对象都有一个objectMonitor对象与之关联monitor对象中主要有如下属性:owner:持有当前objectMonitor的线程地址entrylist:阻塞队列,存放竞争当前monitor......
  • Java synchronized锁升级过程验证
    ​Java对象结构 ​  一个对象包括三部分:对象头实例数据对其填充 对象头:MarkWord:用于存储对象自身运行时的数据,如哈希码(HashCode),GC分代年龄,锁状态标志,......
  • 底层原理解释
    GILGIL是Python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行Python程序的时候会霸占Python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运......
  • 不知道如何分库分表,看完这篇文章,轻松应对工作面试
    一个挺着啤酒肚,身穿格子衫,发际线严重后移的中年男子,手拿着保温杯,胳膊夹着MacBook向你走来,看样子是架构师级别。面试开始,直入正题。面试官: 小伙子,看到你的简历上面写了......
  • 面试官:HashSet 的实现原理是怎样的?底层是什么数据结构?被问到了。。
    来源:https://www.cnblogs.com/LiaHon/p/11257805.html一.HashSet概述HashSet是Java集合Set的一个实现类,Set是一个接口,其实现类除HashSet之外,还有TreeSet,并继承了Collect......
  • redis的底层原理
    1.String:C语言字符串的缺陷:在c语言中,对字符串操作时,char*指针只是指向字符数组的起始位置,而字符数组的结尾位置就用\0表示,意思是指字符串的结束1.获取长度需......
  • Python字典核心底层原理
    字典核心底层原理......
  • 关于rt-thread调度器实现的底层代码分析
      本文使用了rt-thread自带的钩子函数和显示函数进行了实验,从rt-thread自带的延时函数rt_thread_delay()函数入手,对rt-thread系统的调度器进行分析。主要参考资料是野火......
  • K8s小白?应用部署太难?看这篇就够了!
    在云原生趋势下,容器和Kubernetes可谓是家喻户晓,许多企业内部的研发团队都在使用Kubernetes打造DevOps平台。从最早的容器概念到Kubernetes再到DevOps/GitOps整个......
  • 面向对象分析与设计的底层逻辑
    1 面向对象是符合人认识事物的基本方法 01 人是怎么认识事物的 在面向对象出现之前,已有面向过程的分析方法,为什么面向对象被提出了呢?究其本质原因,人们发现面向过程......