您的位置:首页 > 编程语言 > Java开发

Java并发读书学习笔记(九)——性能与可伸缩性

2018-04-01 23:48 495 查看

9.1 对性能的思考

想要通过并发来获得更好的性能,需要努力做好两件事情:更有效地利用现有处理资源,以及在出现新的处理资源时使程序尽可能地利用这些资源。从性能监视的视角看,CPU需要尽可能保持忙碌状态。如果程序是计算密集型的,那么可以增加处理器来提高性能。如果因为程序无法使用现有的处理器保持忙碌状态,那么增加再多的处理器也无济于事。通过将应用程序分解到多个线程上执行,使得每个处理器都执行一些工作,从而使所有CPU都保持忙碌状态。
9.1.1 性能与可伸缩性在并发应用程序中针对可伸缩性进行设计和调整时所采用的方法和传统的性能调优方法截然不同。当进行性能调优时,其目的通常是用更小的代价完成相同的工作。在进行可伸缩性调优时,其目的是将问题的计算并行化,从而能利用更多的计算资源来完成更多的工作。

9.2 Amdahl定律

Amdahl定律描述的是:在增加计算资源的情况下,程序在理论上能够实现最高加速比,这个值取决于程序中可并行组件与串行组件所占的比重。

9.3 线程引入的开销

但线程程序既不存在线程调度,也不存在同步开销,而且不需要使用锁来保证数据结构的一致性。在多个线程的调度与协调过程中都需要一定的性能开销,对于为了提升性能而引入的线程来说,并行带来的线程提升必须超过并发导致的开销。
9.3.1 上下文切换如果主线程是唯一的线程,那么它基本上不会被调度出去。另一方面,如果可运行的线程数大于CPU的数量,那么操作系统会将某个正在运行的线程调度出来,从而使其他线程能够使用CPU。这将导致一次上下文切换,在这个过程中将保存当前运行线程的执行上下文,并将新调度进来的线程的执行上下文设置为当前上下文。
9.3.2 内存同步同步操作的性能开销包括多个方面。在synchronized和volatile提供的可见性保证中可能会使用一些特殊指令,即内存栅栏。内存栅栏可以刷新缓存,使缓存无效,刷新硬件的写缓存,以及停止执行管道,内存栅栏可能同样会对性能带来间接的影响,因为它们将抑制一些编译器优化操作。在内存栅栏中,大多数操作都是不能被重排序的。
9.3.3 阻塞非竞争的同步可以完全在JVM中处理,而竞争的同步可能需要操作系统的介入,从而增加开销。当在锁上发生竞争时,竞争失败的线程肯定会阻塞。JVM在实现阻塞行为时,可以采用自旋等待或者通过操作系统挂起被阻塞的线程。这两种方式的效率高低,要取决于上下文切换的开销以及在成功获取锁之前需要等待的时间。如果等待时间较短,则适合采用自旋等解决方式,而如果等待时间较长,则适合采用线程挂起方式。有些JVM根据历史等待时间的分析数据在这两者之间进行选择,但是大多数JVM在等待锁时都只是将线程挂起。

9.4 减少锁的竞争

有3种方式可以降低锁的竞争程度:减少锁的持有时间;降低锁的请求频率;使用带协调机制的独占锁,这些机制允许更高的并发性。
9.4.1 缩小锁的范围降低发生竞争的可能性的一种有效方式就是尽可能缩短锁的持有时间。
9.4.2 减小锁的粒度另一种减小锁的持有时间的方式是降低线程请求锁的频率。这可以通过锁分解和锁分段等技术来实现,在这些技术中将采用多个相互独立的锁来保护独立的状态变量,从而改变这些变量在之前由单个锁来保护的情况。这些技术能减小锁操作的粒度,并能实现更高的可伸缩性,然而,使用的锁越多,那么发生死锁的风险就越高。
9.4.3 锁分段在某些情况下,可以将锁分解技术进一步扩展为对一组独立对象上的锁进行分解,这种情况被称为锁分段。
9.4.4 避免热点域当每个操作都请求多个变量时,锁的粒度将很难降低。这是在性能与可伸缩性之间相互制衡的另一个方面,一些常见的优化措施,例如将一些反复计算的结果缓存起来,都会引入一些热点域,而这些热点域往往会限制可伸缩性。
9.4.5 一些代替独占锁的方法第三种降低竞争锁的影响的技术就是放弃使用独占锁,从而有助于使用一种友好并发的方式来管理共享状态。例如,使用并发容器,读-写锁,不可变对象以及原子变量。
9.4.6 监测CPU的利用率如果CPU没有得到充分利用,有以下原因:负载不充足;I/O密集;外部限制;锁竞争。
9.4.7 不要使用对象池在并发应用程序中,对象池的表现十分糟糕。当线程分配新的对象时,基本上不需要在线程之间进行协调,因为对象分配器通常会使用线程本地的内存块,所以不需要在堆数据结构上进行同步。然而,如果这些线程从对象池中请求一个对象,那么久需要通过某种同步来协调对对象池数据结构的访问,从而可能使某个线程被阻塞。如果某个线程由于锁竞争而被阻塞,那么这种阻塞的开销将是内存分配操作开销的数百倍,因此即使对象池带来的竞争很小,也可能形成一个可伸缩瓶颈。虽然这看似一种性能优化技术,但实际上却会导致可伸缩性问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java 并发 性能 伸缩性