并发编程的最主要目的是提升程序的运行性能,线程可使程序更加充分的利用系统的可用处理能力,从而提升系统的资源利用率。然而使用多线程时也会引入额外的开销,这些开销包括:线程之间的协调(加锁,内存同步等)、增长的的上下文切换、线程的建立和销毁和线程的调度等等。若是过分以及不恰当的使用线程,这些开销甚至会抵消因为提升吞吐量、计算能力带来的性能提高。一个设计糟糕的多线程程序其性能可能比相同功能的串行程序效率还低。java
提高性能意味着用更少的资源作更多的事情。资源的范围很广,好比CPU,内存,网络带宽,IO,磁盘空间等等。当操做性能因为某种特定的资源而受到限制时,咱们一般称为资源密集型操做,好比CPU密集型等等。编程
要想经过并发来得到良好的性能,须要努力作好两件事:要有效的利用现有的资源,以及新的处理资源出现时程序可以有效的利用新增的资源。从性能监视的视角来看,CPU须要尽量保持忙碌状态(固然这不意味着把CPU用在一些无用的计算上)。安全
应用程序的性能能够经过多个指标来衡量,好比一些指标(服务时间,等待时间)用来衡量运行速度,另外一些指标(生产量、吞吐量)来衡量处理能力。所以,“多快”、“多少”是性能优化的两个不一样方向,它们相互独立,有时甚至是互相矛盾的。所以,在优化以前必需要先确保如下几点:性能优化
第一,首先使程序正确,而后再提升运行速度,避免不成熟的优化。有些同步加锁的方法看上去彷佛能够被一些“聪明”的减小同步的方法所取代,但这每每会引起并发错误,并发错误是最难追踪和消除的,这无疑于填小坑,挖大坑。网络
第二,肯定目标,更快的含义是什么?在什么条件下运行更快?是在高负载仍是低负载?是大数据量仍是小数据量?对目前的情况以及目标情况都要有清晰地认识;多线程
第三,以测试为基准,不要猜想。并发
在有些问题中,可用资源越多,那么问题的解决速度越快,好比收割庄稼,人越多则收割越快,有些任务是串行的,即便增长资源也不能提升速度。程序也是同样的,它由一些串行的和并行的程序组合而成,Amdahl定律描述的是:在增长计算资源的状况下,程序在理论上可以实现最高加速比,这个值取决于程序中并行组件与串行组件所占的比重。用公式表示为:性能
Speedup <= 1/(F+(1-F)/N)测试
Speedup 表示最高加速比,F表示程序中必须被串行的部分,N表示程序处理器的数量。当N趋向于无穷大时,最高的加速比倾向于1/F。若是程序中的串行程序占比10%,那么最高的加速比接近10。大数据
要想算出程序中串行执行的比例其实很困难。可是Amdahl定律的出现却给咱们提供了一些优化的思路。好比锁分段。根据Amdahl定律,随着处理器数量的增长,锁分段的效率要比独占锁和锁分解的效率高,也更能充分利用多处理器的能力。ConcurrentHashMap之因此有较高的性能就是使用了锁分段技术。
咱们知道,串行程序会下降程序的可伸缩性,而线程的上下文切换也会下降性能,而在锁上等待会同时致使以上两种问题。所以,减小锁的竞争可提升程序的伸缩性和性能。有两个因素将影响在锁上发生竞争的可能性:锁得请求频率和每次持有锁的时间。二者的乘积越小则锁的竞争越小。如下将介绍几种减小锁竞争的方法:
第一,减小锁持有的时间(快进快出)。缩小锁的范围,只在须要锁操做的程序上使用锁,将锁无关的操做移出同步代码块。
第二,下降锁的请求频率。减少锁的粒度,这能够经过锁分解和锁分段技术实现。
第三,使用带有协调机制的独占锁,这些机制容许更高的并发性。好比咱们能够用现有的并发容器替换掉同步容器以及使用原子类和读写锁。由于java自带的并发容器已经实现了很好的协调机制,咱们能够直接使用提升效率。
最后要说的是性能优化是一个持续的、无止境的过程。所以,在实际优化过程当中要有明确的目标,在确保程序安全性和正确性的基础上按部就班的去展开,避免盲目和过分优化。