《实战 Java 高并发程序设计》笔记——第4章 锁的优化及注意事项(一)

声明:

本博客是本人在学习《实战 Java 高并发程序设计》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。

本博客已标明出处,如有侵权请告知,马上删除。

“锁” 是最常用的同步方法之一。在高并发的环境下,激烈的锁竞争会导致程序的性能下降。所以我们自然有必要讨论一些有关 “锁” 的性能问题以及相关一些注意事项。比如:避免死锁、减小锁粒度、锁分离等。

在多核时代,使用多线程可以明显地提高系统的性能。但事实上,使用多线程的方式会额外增加系统的开销。

对于单任务或者单线程的应用而言,其主要资源消耗都花在任务本身。它既不需要维护并行数据结构间的一致性状态,也不需要为线程的切换和调度花费时间。但对于多线程应用来说,系统除了处理功能需求外,还需要额外维护多线程环境的特有信息,如线程本身的元数据、线程的调度、线程上下文的切换等。

事实上,在单核 CPU 上,采用并行算法的效率一般要低于原始的串行算法的,其根本原因也在于此。因此,并行计算之所以能提高系统的性能,并不是因为它 “少干活” 了,而是因为并行计算可以更合理地进行任务调度,充分利用各个 CPU 资源。因此,合理的并发,才能将多核 CPU 的性能发挥到极致。

4.1 有助于提高 “锁” 性能的几点建议

“锁” 的竞争必然会导致程序的整体性能下降。为了将这种副作用降到最低,我这里提出一些关于使用锁的建议,希望可以帮助大家写出性能更为优越的程序

4.1.1 减小锁持有时间

对于使用锁进行并发控制的应用程序而言,在锁竞争过程中,单个线程对锁的持有时间与系统性能有着直接的关系。如果线程持有锁的时间很长,那么相对地,锁的竞争程度也就越激烈。可以想象一下,如果要求 100 个人各自填写自己的身份信息,但是只给他们一支笔。那么如果每个人拿着笔的时间都很长,总体所花的时间就会很长。如果真的只能有一支笔共享给 100 个人用,那么最好就让每个人花尽量少的时间持笔,务必做到想好了再拿笔写,千万不可拿着笔才去思考这表格应该怎么填。程序开发也是类似的,应该尽可能地减少对某个锁的占有时间,以减少线程间互斥的可能。以下面的代码段为例:

在这里插入图片描述

syncMethod() 方法中,假设只有 mutextMethod() 方法是有同步需要的,而 othercode1() 和 othercode2() 并不需要做同步控制。如果 othercode1() 和 othercode2() 分别是重量级的方法,则会花费较长的 CPU 时间。此时,如果在并发量较大,使用这种对整个方法做同步的方案,会导致等待线程大量增加。因为一个线程,在进入该方法时获得内部锁,只有在所有任务都执行完后,才会释放锁。

一个较为优化的解决方案是,只在必要时进行同步,这样就能明显减少线程持有锁的时间,提高系统的吞吐量

在这里插入图片描述

在改进的代码中,只针对 mutextMethod() 方法做了同步,锁占用的时间相对较短,因此能有更高的并行度。这种技术手段在 JDK 的源码包中也可以很容易地找到,比如处理正则表达式的 Pattern 类:

在这里插入图片描述

matcher() 方法有条件地进行锁申请,只有在表达式未编译时,进行局部的加锁。这种处理方式大大提高了 matcher() 方法的执行效率和可靠性。

注意:减少锁的持有时间有助于降低锁冲突的可能性,进而提升系统的并发能力。

4.1.2 减小锁粒度

减小锁粒度也是一种削弱多线程锁竞争的有效手段。这种技术典型的使用场景就是 ConcurrentHashMap 类的实现。大家应该还记得这个类吧!在 “3.3 JDK的 并发容器” 一节中,我向大家介绍了这个高性能的 HashMap。但是当时我们并没有说明它的实现原理。这里,让我们更加细致地看一下这个类。

对于 HashMap 来说,最重要的两个方法就是 get() 和 put() 。一种最自然的想法就是对整个 HashMap 加锁,必然可以得到一个线程安全的对象。但是这样做,我们就认为加锁粒度太大。对于 ConcurrentHashMap,它内部进一步细分了若干个小的 HashMap,称之为段(SEGMENT)。默认情况下,一个 ConcurrentHashMap 被进一步细分为 16 个段

如果需要在 ConcurrentHashMap 中增加一个新的表项,并不是将整个 HashMap 加锁,而是首先根据 hashcode 得到该表项应该被存放到哪个段中,然后对该段加锁,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bm1998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值