-
想通过并发获得更好的性能,需要努力做好两件事情:
- 更有效利用现有资源
- 再出现新的处理资源时是程序尽可能地利用这些新的资源
-
可伸缩性:当增加计算资源时(CPU/内存/存储容量/I/O带宽),程序的吞吐量或处理能力能相应地增加
-
Amdahl定律:在增加计算资源的情况下,程序在理论上能够实现最高加速比,这个值取决于程序中可并行组件与串行组件所占的比重:
-
最高加速比(F为串行执行的部分,N为处理器个数):seedup小于等于(1/(F+(1-F)/N))
-
利用率:加速比除以处理器数量
-
线程引入的开销
-
上下文切换:实际开销随平台的不同而变化,大多数通用处理器,相当于5000-10000个时钟周期,也就是几微秒
-
内存同步
-
阻塞
减少锁的竞争
-
并发程序中,对可伸缩性的最主要威胁就是独占方式的资源锁
-
降低锁竞争程度:
- 减少锁的持有时间
- 降低锁的请求频率
- 使用带有协调机制的独占锁,这些机制允许更高的并发性
-
减小锁的范围(快进快出)
-
减小锁的粒度:
- 锁分解:相互独立的状态变量用不同的锁来保护
- 锁分段:ConcurrentHashMap包含了16个锁
-
避免热点域:
- 热点域:将反复计算的结果缓存起来,计算HashMap的size,引入计数器,插入和移除元素时更新,这样可以优化开销,但会降低可伸缩性
- ConcurrentHashMap为每个分段维护一个独立的计数,并通过每个分段的锁来维护这个值,size将对每个分段进行枚举并将每个分段中的计数器相加,而不是维护一个全局计数
-
替代独占锁:
- ReadWriteLock:读操作可以同时访问共享资源
- 原子变量:提供了整数/对象引用上的细粒度原子操作,使用了现代处理器中提供的底层并发原语,可以降低热点域的更新开销
-
CPU没有充分利用:
- 负载不充足
- I/O密集
- 外部限制
- 锁竞争
-
对象池:对象能被循环使用,而不是由GC回收并在需要时重新分配;但要同步机制协调对象池数据结构的访问,通常对象分配的操作开销比同步的开销更低,所以不要用对象池!