synchronized关键字:多线程资源访问同步性与早期效率低下原因 春节 营销推广计划

发布时间 - 2026-01-18 14:10:40    点击率:

目录

1.1 说一说自己对于  关键字的了解

关键字的作用是解决多个线程访问资源的同步性问题。它能够确保被其修饰的方法或者代码块在任何时刻都只能有一个线程执行。

在 Java 的早期版本里,它属于重量级锁,效率较为低下。这是因为监视器锁()是依靠底层的操作系统的 Mutex Lock 来实现的,并且 Java 的线程是映射在操作系统的原生线程之上的。要挂起或者唤醒一个线程,都得依靠操作系统来帮忙完成。操作系统在实现线程之间的切换时,需要从用户态转换到内核态。这种状态之间的转换需要花费相对较长的时间,且时间成本较高。这就是早期效率低的原因所在。庆幸的是,在 Java 6 之后,Java 官方从 JVM 层面进行了较大优化。所以现在的锁效率优化得很不错了。JDK1.6 对锁的实现引入了诸多优化,像自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术,这些技术能减少锁操作的开销。

1.2 说说自己是怎么使用  关键字,在项目中用到了吗

关键字最主要的三种使用方式:

下面我已一个常见的面试题为例讲解一下  关键字的具体使用。

面试时面试官常常会问:“你了解单例模式吗?请给我手写一下单例模式!给我讲讲用双重检验锁方式实现单例模式的原理吧!”

双重校验锁实现对象单例(线程安全)

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'> <pre class="has"><code class="language-java">public class Singleton { private 类型的变量 uniqueInstance 是 volatile 的且为 static 的,它是 Singleton 类型的单例对象。     private Singleton() {     } public static Singleton 获取唯一实例() { 先判断对象是否已经被实例化过,如果没有被实例化过,才进入加锁代码。 如果 uniqueInstance 为 null ,那么 ;如果 uniqueInstance 不为 null ,则 。             //类对象加锁 对 Singleton.class 进行同步操作。 如果 uniqueInstance 为 null ,那么 ;如果 uniqueInstance 不为 null ,则不执行此条件判断 。 Singleton 类创建了一个名为 uniqueInstance 的实例。                 }             }         } 返回唯一实例。     } } </code></pre></p>

另外,需要注意  采用  关键字修饰也是很有必要。

使用关键字进行修饰是很有必要的。这段代码实际上是分三步来执行的:第一步,进行某个操作;第二步,执行另一个动作;第三步,完成最后的步骤。

为  分配内存空间初始化 将  指向分配的内存地址

但是 JVM 具备指令重排的特性,所以执行顺序有可能变为 1->3->2。在单线程环境中,指令重排不会出现问题,然而在多线程环境下,会致使一个线程获取到尚未初始化的实例。比如,线程 T1 执行了 1 和 3,这时 T2 调用某个对象后发现该对象不为空,于是就进行返回,但此时该对象还未被初始化。

使用它能够禁止 JVM 的指令重排,从而确保在多线程环境下可以正常运行。

1.3 讲一下  关键字的底层原理

  关键字底层原理属于 JVM 层面。

①  同步语句块的情况

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'> <pre class="has"><code class="language-java">类 SynchronizedDemo 是一个公共类。     public void method() {         synchronized (this) { System 输出打印“synchronized 代码块”。         }     } } </code></pre></p>

使用 JDK 自带的 javap 命令来查看类的相关字节码信息。首先要切换到类的对应目录,接着在该目录下执行 javac.java 命令,以生成编译后的.class 文件。之后再执行 javap -c -s -v -l.class 命令。

  关键字原理

从上面我们可以看出:

同步语句块的实现运用的是  指令与  指令。其中,  指令所指的是同步代码块的起始位置,而  指令所指明的是同步代码块的结束位置。当执行指令时,线程会尝试获取锁。锁存在于每个 Java 对象的对象头中,通过这种方式来获取锁,这也是 Java 中任意对象可以作为锁的原因。当锁的计数器为 0 时,线程可以成功获取锁,获取后将锁的计数器设为 1,即加 1。相应地,在执行指令后,会将锁的计数器设为 0,表明锁被释放。获取对象锁失败时,当前线程会进行阻塞等待。它会一直等待,直到锁被另一个线程释放。

②  修饰方法的的情况

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'> <pre class="has"><code class="language-java">在该类中可以看到对同步机制的运用和相关操作的实现。 public 方法处于同步状态。 System 输出打印 "synchronized 方法"。     } } </code></pre></p>

修饰的方法没有特定的指令。取而代之的是标识,此标识表明该方法是同步方法。JVM 通过这个访问标志来辨别一个方法是否被声明为同步方法,进而执行相应的同步调用。

说说 JDK1.6 之后的关键字在底层进行了哪些方面的优化呢?可以详细地介绍一下这些优化的情况吗?

JDK1.6 对锁的实现做了大量优化。其中包括引入偏向锁技术,以减少锁操作的开销。还引入了轻量级锁技术,同样能降低锁操作的开销。同时引入了自旋锁技术,有助于减少锁操作的开销。也引入了适应性自旋锁技术,可减少锁操作的开销。并且引入了锁消除技术,能减少锁操作的开销。还引入了锁粗化技术,可降低锁操作的开销。

锁主要有四种状态,分别是:无锁状态;偏向锁状态;轻量级锁状态;重量级锁状态。它们会随着竞争的加剧而逐步升级。需要注意的是,锁可以升级但不可降级,这种策略的目的是提升获得锁和释放锁的效率。

①偏向锁

引入偏向锁的目的与引入轻量级锁的目的较为相似。二者都是在没有多线程竞争的前提下,旨在减少传统重量级锁使用操作系统互斥量所带来的性能消耗。然而,二者存在差异:轻量级锁在无竞争的情况下,会利用 CAS 操作来替代使用互斥量;而偏向锁在无竞争的情况下,能够将整个同步过程消除掉。

偏向锁的“偏”即偏心之意,意味着会倾向于第一个获取它的线程。若在后续执行中,此锁未被其他线程获取,那么持有偏向锁的线程就无需进行同步。关于偏向锁的原理,可查看《深入理解 Java 虚拟机:JVM 高级特性与最佳实践》第二版的 13 章第三节锁优化。

在锁竞争激烈的场合,偏向锁会失效。因为这种场合下,每次申请锁的线程很可能都不一样。所以在这种场合不应使用偏向锁,否则会得不偿失。需要注意的是,偏向锁失败后,不会立即膨胀为重量级锁,而是先升级为轻量级锁。

② 轻量级锁

如果偏向锁失败,虚拟机不会立刻升级为重量级锁。它会尝试使用一种优化手段,这种手段称为轻量级锁(1.6 之后加入的)。轻量级锁并非是为了替代重量级锁,其本意是在没有多线程竞争的情况下,减少传统重量级锁使用操作系统互斥量所产生的性能消耗,因为使用轻量级锁时,无需申请互斥量。另外,轻量级锁在加锁时用到了 CAS 操作,在解锁时也用到了 CAS 操作。关于轻量级锁加锁和解锁的原理,可以查看《深入理解 Java 虚拟机:JVM 高级特性与最佳实践》第二版的 13 章第三节锁优化。

轻量级锁能提升程序同步性能的依据是绝大部分锁在整个同步周期内不存在竞争,这是经验数据。若没有竞争,轻量级锁利用 CAS 操作避免了互斥操作的开销。然而,若存在锁竞争,除了互斥量开销外,还会额外发生 CAS 操作,所以在有锁竞争的情况下,轻量级锁比传统的重量级锁更慢。如果锁竞争激烈,那么轻量级将很快膨胀为重量级锁!

③ 自旋锁和自适应自旋

轻量级锁失败后,虚拟机为避免线程在操作系统层面真实挂起,还会进行一种被称为自旋锁的优化手段。

互斥同步对性能影响最大的方面是阻塞的实现。因为挂起线程的操作以及恢复线程的操作都需要转入内核态去完成,而用户态转换到内核态是会耗费时间的。

一般线程持有锁的时间不会太长。因为时间不长,仅仅为这点时间去挂起线程或恢复线程是不值得的。所以,虚拟机的开发团队进行了这样的考虑:能否让后面来请求获取锁的线程等待一会儿而不被挂起呢?看看持有锁的线程是否能很快释放锁。要让一个线程等待,只需让线程执行一个忙循环(自旋),而这种技术就被称作自旋。

百度百科对自旋锁的解释:

什么是自旋锁?自旋锁是为了实现对共享资源的保护而提出的一种锁机制。实际上,自旋锁和互斥锁较为相似,它们都是为了解决对某一项资源的互斥使用问题。不管是互斥锁,还是自旋锁,在任何一个时刻,最多只能有一个保持者,也就是说,在任何一个时刻,最多只能有一个执行单元获得锁。然而,两者在调度机制方面略有差异。互斥锁的情况是,如果资源已经被占用,那么资源申请者就只能进入睡眠状态。而自旋锁则不会导致调用者睡眠,倘若自旋锁已经被其他执行单元所保持,调用者就会一直循环,查看该自旋锁的保持者是否已经释放了锁,“自旋”这个词正是因为这样的情况而得名。

自旋锁在 JDK1.6 之前就已被引入,但其默认是关闭的,需通过--XX:+参数来开启。JDK1.6 及之后,就改为默认开启了。需注意,自旋等待不能完全替代阻塞,因其仍需占用处理器时间。若锁被占用时间短,效果就好;若锁被占用时间长,效果则不佳。自旋等待的时间必须有限度。如果自旋达到了限定的次数,然而仍然没有获得锁,那么就应当挂起线程。自旋的次数默认是 10 次,用户能够通过修改--XX:来对其进行更改。

另外,在 JDK1.6 中引入了一种自旋锁。这种自旋锁是自适应的。自适应的自旋锁带来的改进在于:自旋的时间不再是固定的了。它会根据前一次在同一个锁上的自旋时间以及锁的拥有者的状态来决定。这样一来,虚拟机变得越来越“聪明”了。

④ 锁消除

锁消除理解起来较为容易。它的意思是,在虚拟机中,即使是编译器在运行时,如果检测到那些共享数据不可能存在竞争的情况,那么就会执行锁消除操作。锁消除能够节省那些没有意义的请求锁所耗费的时间。

⑤ 锁粗化

我们在编写代码时,原则上总是推荐把同步快的作用范围限制得尽量小。只在共享数据的实际作用域进行同步,这样做是为了让需要同步的操作数量尽可能变小。如果存在锁竞争,等待线程就能尽快拿到锁。

大部分情况下,上面的原则没问题。然而,若一系列连续操作都针对同一个对象反复进行加锁和解锁,就会导致很多不必要的性能消耗。

1.5 谈谈 和 的区别

① 两者都是可重入锁

两者均为可重入锁。“可重入锁”的概念为:自身能够再次获取自身的内部锁。例如,有一个线程获取了某对象的锁,而此时该对象锁尚未释放,当它再次想要获取此对象的锁时依然可以获取。倘若不可锁重入,就会引发死锁。同一个线程每次获取锁,锁的计数器都会自增 1,因此必须等到锁的计数器降为 0 时才能释放锁。

②  依赖于 JVM 而  依赖于 API

依赖于 JVM 得以实现。前面我们提到过,虚拟机团队在 JDK1.6 对该关键字进行了诸多优化,然而这些优化是在虚拟机层面完成的,并未直接呈现在我们面前。它是在 JDK 层面实现的,也就是在 API 层面实现的。实现过程需要 lock()方法和特定的语句块(如 try/ 语句块)配合来完成。因此,我们能够通过查看它的源代码,去了解它是怎样实现的。

③  比  增加了一些高级功能

相比之前,增添了一些较为高级的功能。主要体现在以下三个方面:其一,等待的过程可以被中断;其二,能够实现公平锁;其三,可以实现选择性通知,也就是锁能够绑定多个条件。

如果你想使用上述功能,那么选择是一个不错的选择。

④ 性能已不是选择标准

在 JDK1.6 之前, 的性能与 相比差很多。具体表现为:随着线程数的增加,关键字的吞吐量下降得极为严重,而 则基本保持在一个较为稳定的水平。我认为这从侧面反映出,关键字还有很大的优化空间。后续的技术发展也证实了这一点,我们之前讲过在 JDK1.6 之后,JVM 团队对该关键字做了很多优化。JDK1.6 之后, 和  的性能大致相同。因此,网络上那些以性能为由选择  的文章是错误的!JDK1.6 之后,性能不再是选择 和 的影响因素!并且,虚拟机在未来的性能改进中会更倾向于原生的,所以还是建议在能够满足需求的情况下,优先考虑使用关键字来进行同步!优化后的和一样,在很多地方都是用到了CAS操作。

1.6 说说  关键字和  关键字的区别

关键字和关键字比较

1.7 java.util.

j.u.c 下有大量的应用,这些应用在各个基础类和工具栏中,它们构成了 Java 并发包的基础。后续进行并发编程学习时,可以按照这个路线图来进行学习。


# synchronized关键字:多线程资源访问同步性与早期效率低下原因  # synchronized关键字  # 多线程资源访问同步性与早期效率低下原因  # 的是  # 互斥  # 是在  # 就会  # 操作系统  # 挂起  # 都是  # 情况下  # 加锁  # 引入了  # 多线程  # 进行了  # 是一个  # 它会  # 需要注意  # 给我  # 多个  # 自适应  # 解锁  # 有一个  # 商洛珠宝网站建设  # 官网SEO网站建设  # 北京网站建设详细方案  # 做营销怎样引流推广产品  # 网站怎么做推广方案  # 新北区百度网站优化排名  # 大连建设网站企业  # 邵阳网站建设怎么做  # 金华大型网站建设  # 廊坊网站建设报价单  # 麻城店铺推广招聘网站有哪些  # 顺德区外贸推广营销中心  # 怎么样设计网站推广产品  # 营销培训推广优势  # 西安抖音营销推广收费  # 红包营销推广项目  # 企业微网站营销推广  # 龙江网站建设方案  # 海安市网站推广方案批发  # 广安品牌网站建设 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 福建百度推广关键词优化指南,广宗本地网站建设  数字化支付时代,如何关闭微信指纹支付?看这里   SEO薪资这些,你也能月入过万!,天水网站建设公司  佛山品牌SEO推广外包,专业助力企业腾飞,重庆如何进行seo  黄岛SEO优化,打造高效网站,提升品牌影响力的关键策略,人设营销推广方案  SEO平台位置介绍,优化步骤与实战方法,安阳外贸网站推广优化  介绍来宾SEO优化价格,性价比与效果并重的选择之路,厦门湖里区网站优化公司  广州百度推广如何提升转化率?,平山品牌网站建设报价  揭秘成功的自媒体营销秘籍,如何让你的品牌在浩瀚的内容海洋中脱颖而出?,网站设计建设报告范文  揭秘自媒体营销的 黄金法则,如何让你的品牌在竞争激烈的市场中脱颖而出,网站推广水文化  SEO快速提升:让你的网站排名瞬间飙升的秘诀,网站建设的发展目标  西安SEO首页优化招聘,助力企业提升搜索引擎排名,抢占市场先机,柏乡seo网站优化  SEO分类:从基础到进阶,全面解析SEO优化的关键要素,新建设网站排名  性价比之选,介绍高SEO排名的秘密武器,seo网站建设规划  如何设置福建百度推广关键词才能达到**效果,摄影师网站怎么做推广赚钱  手机相册爆满删又难恢复慢?简单万无一失备份方法快来看   广州百度推广竞价,助力企业数字化营销升级,律师网站推广的广告语  SEO营销技术培训,助力企业互联网时代的腾飞之路,seo后台托管费用  福建百度推广的费用如何取出来?,丹东网站建设与维护推广  SEO火爆公开课,介绍搜索引擎优化之路,助力网站流量翻倍!,鹤岗seo公司优选火星  广州百度推广途径全解析,顺庆区营销推广大厦邮编  广州百度推广圈词策略的优化之道,常州网站建设顾问  白帽SEO,耐心与坚持,见证网站排名的稳步提升,福建网站怎么优化  SEO做好,企业网站流量翻倍的关键,seo白帽技术有哪些  建瓯SEO排名,介绍提升网站流量与品牌影响力的方法,上海优化seo平台  沙溪网站SEO优化步骤全介绍,助力网站排名,提升企业影响力,property 对seo  一站式SEO服务,助力企业高效提升网站排名,抢占市场先机,seo伪原创方法  SEO策划:让你的网站迅速脱颖而出的秘诀,seo优化和技巧  SEO爱站:提升网站排名,赢得流量的秘密武器,优化网站设计价格多少  云浮SEO优化厂家,提升网站排名的关键策略,盐城网站建设银行工作  SEO技术如何通过优化提升网站流量与排名,四平网站优化公司  SEO而且:打造高效网站流量增长的秘密武器,滨江网站推广营销  揭秘自媒体营销的秘密武器,如何让内容脱颖而出并实现流量变现,网站推广组织架构  SEO组织:让您的网站流量倍增的秘密武器,seo 绩效标准  短|视频|SEO引流,打造爆款短|视频|,提升企业品牌影响力,seo建设属于什么行业  成华区短|视频|SEO技术介绍,助力短|视频|内容在搜索引擎中脱颖而出,乌海网站优化厂家  以用户体验为核心,打造SEO新境界,seo基础入门知识大全  菲律宾*SEO,揭秘成功的秘诀与策略,安阳网站推广设计招聘网  深圳SEO行业最新动态,关键词布局与搜索引擎优化步骤,阿文seo  沈阳SEO培训,提升网络可见度的关键途径,优化seo 推广  SEO在国外市场的崛起,影响与启示,广州seo服务推广价格  揭秘黑客SEO优化联盟,如何让你的网站在搜索引擎中脱颖而出?,二级网站内容建设要求  从镜像中汲取力量,探索自媒体的SEO奥秘,唐山网站建设制作报价  SEO收集:如何通过有效数据收集提升网站排名,鞍山商城网站建设报价  2025年抖音超长知识视频成现象级爆款,你看过吗?   SEO好吗?助力网站成功的关键之道,网站优化方案范文怎么写  广州百度推广门店与网站的优化策略,邢台手机网站建设宣传  三八节抖音成女性魅力舞台!职场精英自信讲述奋斗故事   青岛SEO优化,打造你的在线品牌之路,seo文章制作  SEO批量挖掘长尾关键词的方法,精准定位,提升网站流量,南阳seo公司稳健火星