java并发编程实践-性能和可伸缩性
性能的思考
与单线程相比,使用多线程总会引入一些性能的开销,这些开销包括:与协调线程相关的开销(加锁、信号、内存同步),增加上下文的切换,线程的创建和消亡。
我们希望CPU做有用的事情,单线程程序即不存在调度问题,也不存在同步开销,不需要使用锁来保证数据结构的一致性。调度和线程内部的协调都要付出性能的开销;
如果可运行的线程的数目大于CPU的数量,那么OD最终会强行换出正在执行的线程,从而使其他线程能够使用CPU。这会引起上下文切换,他会保存当前运行线程的上下文,并重新调入线程的执行上下文。
切换上下文是要付出代价的;线程的调度需要操控OS和JVM中共享的数据结构;当一个新的线程呗换入后,他所需要的数据可能不在当前处理器本地的缓存中,所以切换上下文会引起缓存缺失的小恐慌,因此线程在第一次调度的时候会运行的稍微慢一些;
关键点:当线程因为竞争一个锁而阻塞时,JVM通常会将这个线程挂起,允许他被换出;如果线程频繁发生阻塞,那线程就不能完整的使用它的调度限额了,一个程序发生越多的阻塞(阻塞IO、等待竞争所、或者等待条件变量)备注:死锁可能会导致线程切换频繁,与受限于CPU的程序相比,就会造成越多的上下文切换,这增加了调度的开销,并减少了吞吐量;高内核占用率(超过10%)通常象征繁重的调度活动,这很可能是由I/O阻塞,或者竞争锁引起的。