如何让多线程优于单线程程序,很简单的一个原则:多线程并行带来的优势要优于引入多线程带来的开销。
下面来讨论多线程在哪些方面会带来开销:
1,切换上下文
产生原因举例:多线程竞争锁时被阻塞,该线程就会阻塞,会被jvm挂起,造成上下文切换,目的是为了新线程分配新的资源。
如果线程数多于cpu内核数多会引起上下文的切换。
如何分析上下文切换开销太大:unix系列的vmstat及windows系统的perfmon都能报告上下文切换占用时间,如果超过内核的10%时间,那就很有可能是线程阻塞
或者竞争锁引起。
vmstat命令各个列的含义如下表:
列名
含义
r
运行队列的长度,即等待执行的线程数目
b
处于阻塞状态或者等待IO完成状态的线程数目
in
系统中断的数目
cs
上下文切换的数目
us
CPU执行用户态线程的时间占比
sys
CPU执行系统态线程占用的时间占比,包含内核和中断两部分
wa
CPU处于等待状态的时间占比(CPU等待状态即所有线程都处于被阻塞或者等待IO完成状态)
id
CPU处于完全空闲状态的时间占比
2,内存同步
synchronized,volatile会设置memory barrier(内存关卡),要求必需使用内存关卡来进行缓存刷新,缓存无效,形成性能瓶颈,影响重排序
如何进行优化:逃逸分析方法,简单的理解就是看该本地对象是否未被堆中对象引用,如果没有就可进行锁消除等操作,很多工作实际在jvm中的jit进行优化编译时
就会做掉,比如常用的锁优化机制:自旋锁、锁消除、锁粗化、偏向锁等。
3,阻塞
非竞争的同步由jvm完全掌控,而竞争的同步可能会需要os的活动,从而引起较大的开销,既然有竞争,竞争失败的线程肯定会引起阻塞。
如果处理阻塞;两种方式:自旋、挂起
自旋应用场景:等待时间短
挂起:适合等待时间长