性能问题
尽管使用多线程的初衷是提高性能,但与单线程的方法相比,多线程会引起一些额外的开销。造成这些开销的操作包括:
- 线程之间的协调
- 线程上下文切换
- 线程的创建和销毁
- 线程调度
并发编程的性能开销主要包括以下方面:
- 线程上下文切换
上下文的切换发生在线程调度过程中,一个线程的时间片用完,将执行权限释放,下一个线程执行,为了使线程在下一次继续执行时能正确地继续,需要保存线程执行的状态,包括局部变量、PC值以及其他的栈数据。并且在新线程切入后,本地缓存数据是前面线程的,线程首次运行会相对缓慢,因为缓存命中基本没有。
- 内存同步
主要是同步机制带来的开销,在锁和volatile提供的可见性保证时用到的内存屏障指令,会使本地缓存失效,也会限制处理器的优化(指令重排序)。
同步会增加共享内存总线上的通信量,总线的带宽是有限的,且所有的处理器共享这条总线。
- 阻塞
另外由于锁机制的存在,一个获得时间片的线程可能会阻塞等待获取锁,等待的线程可能会自旋等待或者可能会被OS挂起,自旋等待如果在时间片内也没有获取到锁或者被挂起就导致一次无谓的上下文切换,且即使自旋等待等到了锁,线程也由于部分阻塞无法完整的使用时间片。
对策
针对以上的性能问题,主要有以下几个缓解方法
- 减少锁的竞争(减少独占)
主要包含:
- 缩小锁的范围
- 降低锁的粒度,如分段锁
- 减少独占锁
- 减少上下文切换的开销
参考资料
[1] Java并发编程实战
网友评论