说到多线程,就不得不说说Synchronized。重要性不言而喻。今天主要分享一下Synchronized的底层实现。synchronized关键字解决了多线程间资源访问的同步问题。synchronized翻译成中文就是同步的意思,也叫“同步锁”。synchronized的作用是保证在同一时刻,只有一个线程会执行修改后的代码块或方法,从而达到保证并发安全的效果。Synchronized的使用主要有3种方式:1.修改实例方法:作用于当前实例,加锁publicsynchronizedvoidmethod(){//code}2.修改静态方法:作用于当前类对象,加锁publicstaticsynchronizedvoidmethod(){//code}3.修改后的代码块:指定锁对象,给给定的对象加锁synchronized(this){//code}Synchronized的底层实现synchronized的底层实现完全依赖于JVM虚拟机,所以说到synchronized的底层实现,就不得不说到JVM内存中数据的存储:Java对象头,Monitor对象监视器。1、Java对象头在JVM虚拟机中,对象在内存中的存储布局可以分为三个区域:对象头(Header)、实例数据(InstanceData)、对齐填充(Padding)Java对象头主要包括两部分数据:1)类型指针(KlassPointer)是对象指向其类元数据的指针,虚拟机通过这个指针来判断对象是哪个类实例;2)标记字段(MarkWord)用于存储对象自身的运行时间数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,是实现轻量锁和偏向锁的关键。所以,很明显synchronized使用的锁对象是存放在Java对象头中的tag字段中的。2.Monitormonitor被描述为对象监视器,可以类比为一个特殊的房间。这个房间里有一些受保护的数据。监视器保证一次只有一个线程可以进入这个房间来访问受保护的数据。为了握住显示器,离开房间就是释放显示器。下图是synchronized同步代码块的反编译截图,可以清楚的看到monitor的调用。syncrhoized加锁的同步代码块在字节码引擎中执行时,主要是通过锁对象的monitor的获取(monitorenter)和释放(monitorexit)来实现的。3.线程状态流向反映在Monitor上。当多个线程同时请求一个对象监视器时,对象监视器会设置几种状态来区分请求线程:ContentionList:所有请求锁的线程将被放在最前面竞争队列EntryList:ContentionList中的那些线程有资格成为候选人的被移到EntryListWaitSet:那些被调用wait方法阻塞的线程被放到WaitSetOnDeck:任何时候最多有一个线程在竞争锁,这个线程叫做OnDeckOwner:获取锁的线程称为Owner!Owner:释放锁的线程下图反映了一个状态转换关系:同步锁升级锁解决了数据的安全,但也带来了性能下降,热点虚拟机作者发现经查,大多数情况下,被加锁的代码不仅不存在多线程竞争,反而总是被同一个线程多次获取。所以基于这样的概率,synchronized在JDK1.6之后做了一些优化。为了减少获取和释放锁的性能开销,引入了偏向锁和轻量级锁。锁的地位根据竞争程度由低到高。高不断升级。1.NolockNolock没有资源被锁定,所有线程都可以访问和修改同一个资源,但同时只有一个线程可以修改成功。2.偏向锁偏向锁是JDK6引入的一种锁优化。大多数情况下,锁不仅不存在多线程竞争,而总是被同一个线程多次获取。它的引入是为了让线程以更低的代价获取锁。偏向锁。偏向锁将偏向第一个获取它的线程。如果下次执行时锁没有被其他线程获取到,持有偏向锁的线程就永远不需要同步了。3、轻量级锁是指当锁是偏向锁,被其他线程访问时,偏向锁会升级为轻量级锁,其他线程会尝试以自旋的形式获取锁,不会阻塞。从而提高性能。4.重量级锁参考原来的Synchronized实现。重量级锁的特点:当其他线程试图获取锁时,会被阻塞。只有持有锁的线程释放锁后,这些线程才会被唤醒。多于!作者简介:mikechen,高级架构师兼CTO,拥有十??余年BAT架构经验!必读近期热点文章1.史上最全阿里巴巴Java面试题库(2022最新版)2.2022金三银四一线大厂必读题解析合集3.Java多线程与并发系列从0到1全部合集4.JVM(Java虚拟机)从0到1合集5.史上最强消息队列MQ一句话总结!感觉不错,别忘了点赞+转发!
