java并发编程(十)性能与可伸缩行

线程的最主要目的是提高程序的运行性能
要想通过并发来获得更好的性能,需要努力做好两件事情:更有效地利用现有处理资源,以及在出现新的处理资源时使程序尽可能地利用这些新资源。从性能监视的视角来看,CPU需要尽可能保持忙碌状态。这也就是程序的性能与可伸缩性。

线程引入的开销

尽管使用多个线程的目标是提升整体性能,但与单线程的方法相比,使用多个线程总会引人一些额外的性能开销。造成这些开销的操作包括:线程之间的协调(例如加锁、触发信号以及内存同步等),增加的上下文切换,线程的创建和销毁,以及线程的调度等。
一个并发设计很糟糕的应用程序,其性能甚至比实现相同功能的串行程序的性能还要差。
对于为了提升性能而引入的线程来说,并行带来的性能提升必须超过并发导致的开销。

  • 上下文切换
    切换上下文需要一定的开销,而在线程调度过程中需要访问由操作系统和JVM共享的数据结构,但上下文切换的开销并不只是包含JVM和操作系统的开销。当一个新的线程被切换进来时,它所需要的数据可能不在当前处理器的本地缓存中,因此上下文切换将导致一些缓存缺失,因而线程在首次调度运行时会更加缓慢。
  • 内存同步
    同步操作的性能开销包括多个方面。在synchronized和volatile提供的可见性保证中可能会使用一些特殊指令,它们将抑制一些编译器优化操作。在内存栅栏中,大多数操作都是不能被重排序的。
    在评估同步操作带来的性能影响时,区分有竞争的同步和无竞争的同步非常重要。 synchronized机制针对无竞争的同步进行了优化(volatile通常是非竞争的)这个基本的机制已经非常快了,并且JVM还能进行额外的优化以进一步降低或消除开销。因此,不要过度担心非竞争同步带来的开销,我们应该将优化重点放在那些发生锁竞争的地方。
  • 阻塞
    当线程阻塞时,需要被挂起,在这个过程中将包含两次额外的上下文切换,以及所有必要的操作系统操作和缓存操作:被阻塞的线程在其执行时间片还未用完之前就被交换出去,而在随后当要获取的锁或者其他资源可用时,又再次被切换回来。(由于锁竞争而导致阻塞时,线程在持有锁时将存在一定的开销:当它释放锁时,必须告诉操作系统恢复运行阻塞的线程。)

减少锁的竞争

串行操作会降低可伸缩性,并且上下文切换也会降低性能。在锁上发生竞争时将同时导致这两种问题,因此减少锁的竞争能够提高性能和可伸缩性。

  • 缩小锁的范围(“快进快出”)
    降低发生竞争可能性的一种有效方式就是尽可能缩短锁的持有时间。例如,可以将一些与锁无关的代码移出同步代码块,尤其是那些开销较大的操作,以及可能被阻塞的操作,例如l/O操作。
  • 减小锁的粒度
    锁分解和锁分段等技术可以减小锁的粒度,从而降低锁的竞争。
    锁分解:如果一个锁需要保护多个相互独立的状态变量,那么可以将这个锁分解为多个锁,并且每个锁只保护一个变量,从而提高可伸缩性,并最终降低每个锁被请求的频率。
    锁分段:典型的ConcurrentHashMap就是采用了分段锁的思想。锁分段的一个劣势在于:与采用单个锁来实现独占访问相比,要获取多个锁来实现独占访问将更加困难并且开销更高。解决办法参考ConcurrentHashMap的size方法实现。
  • 避免热点域
    每个操作都请求多个变量时,锁的粒度将很难降低。这是在性能与可伸缩性之间相互制 衡的另一个方面,一些常见的优化措施,例如将一些反复计算的结果缓存起来,都会引人一些 “热点域(Hot Field) ”,而这些热点域往往会限制可伸缩性。
  • 一些替换独占锁的方法
    降低竞争锁还有一种方式是放弃使用独占锁,从而有助于使用一种友好并发的方式来管理共享状态。例如,使用并发容器、读·写锁、不可变对象以及原子变量。
    ReadWriteLock实现了一种在多个读取操作以及单个写人操作情况下的加锁规则,比如ReadWriteLock对于只读的数据结构,其中包含的不变性可以完全不需要加锁操作。
    原子变量提供了一种方式来降低更新“热点域"时的开销,例如静态计数器、序列发生器、或者对链表数据结构中头节点的引用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Java并发编程实战》是一本经典的Java并发编程指南,由Brian Goetz等人撰写。这本书针对Java多线程并发编程的实践问题给出了详细的解决方案和最佳实践。 该书的主要内容包括:线程安全性、对象的共享与发布、锁的优化、性能与可伸缩性、构建和组合对象、基础构建模块、任务执、取消与关闭、线程池的使用、显式锁、构建自定义的同步工具等。 通过阅读这本书,读者可以了解Java中的各种并发问题,并学习如何设计和实现线程安全的Java应用。该书引入了很多并发编程的常见问题,例如:竞态条件、死锁、活跃性危险等,并提供了一些模式和技术来解决这些问题。 除了基础知识之外,该书还介绍了一些高级的并发编程概念,例如:并发集合、同步类、线程池等。这些内容将帮助读者更好地理解和利用Java并发编程能力。 总的来说,《Java并发编程实战》是一本权威而实用的Java并发编程指南,适合对多线程编程有一定了解的Java开发人员阅读。通过阅读这本书,读者可以更深入地理解Java并发编程的原理与应用,提高自己的并发编程能力。 ### 回答2: 《Java并发编程实战》是由美国计算机科学家布莱恩·戈策等人合著的一本书,是学习Java并发编程的经典教材。这本书系统地介绍了Java中的多线程、并发和并编程的基本知识和应用。该书分为三个部分,分别是基础篇、高级主题篇和专题扩展篇。 在基础篇中,书中详细介绍了Java内存模型、线程安全性、对象的共享、发布和逸出等概念。同时,还对Java中的锁、线程池、阻塞队列等常用并发工具进了深入讲解,帮助读者理解并发编程的基本原理和机制。 高级主题篇则讨论了一些更加复杂的并发编程问题,如线程间的协作、线程间通信、并发集合类的使用和自定义的同步工具的设计等内容。该篇章通过讲解常见的并发问题和解决方案,提供了应对复杂并发场景的实践经验。 专题扩展篇主要讨论了一些与并发编程相关的主题,如并发性问题的调试与测试、程序性能调优等。这些内容能够帮助读者进一步提升对并发编程的理解和应用水平。 《Java并发编程实战》通过深入浅出的语言和大量实例,帮助读者掌握并发编程的基本概念和技术,为读者提供设计和编写高效多线程程序的实践经验。无论是Java初学者还是有一定经验的开发人员,都可以从中获得丰富的知识和实用的技巧,加速自己在并发编程领域的成长。 ### 回答3: 《Java并发编程实战》是一本经典的Java多线程编程指南,被广泛认可为学习并发编程的必读之作。本书由Brian Goetz等多位并发编程领域的专家合著,内容全面且深入浅出,适合从初学者到高级开发人员阅读。 该书分为四个部分,共16章。第一部分介绍了并发编程的基础知识,包括线程安全性、对象的共享、对象组合等。第二部分讲解了如何构建可复用的并发构件,包括线程安全性、发布与初始化安全性等。第三部分深入讨论了Java并发编程中常见的问题和挑战,例如活跃性、性能与可伸缩性等。第四部分则介绍了一些高级主题,如显式锁、原子变量和并发集合等。 书中包含了大量的示例代码和实践案例,可以帮助读者更好地理解并发编程的概念和技术。此外,本书还提供了一些最佳实践和经验教训,帮助读者避免常见的并发编程陷阱和错误。 《Java并发编程实战》从理论到实践的结合非常好,书中所介绍的内容都是经过实践验证的,具有很高的可靠性和实用性。无论是初学者还是有一定经验的开发人员,都可以从中获得实际应用的知识和经验。 综上所述,如果你想系统地学习Java并发编程,了解如何编写高效、可靠的多线程代码,那么《Java并发编程实战》是一本值得推荐的书籍。它可以帮助你深入理解并发编程的原理和技术,提高自己在并发编程领域的能力和水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值