-
上下文切换
CPU核心(单核CPU或多个CPU的一个核心)通过给每个线程分配CPU时间片,让各线程有执行的机会。时间片非常短,通常为几十毫秒,所以CPU通过不停的切换线程,让人感觉多个线程是同时执行的。
CPU核心在当前线程(A线程)的时间片执行完之后,会切换到下一个线程(B线程)。在切换之前,会保存A线程的状态,以便切回A线程时可以回到上一次的状态。从状态保存到再次加载的过程,就是一次上下文切换。
需要注意的是,上下文切换是开销较大的,过多的上下文切换,会影响多线程的执行速度。所以在开发中可以通过一些方法,尽量减少上下文切换。如:
- 无锁并发编程:volatile关键字、cas算法(Java的Atomic包使用CAS算法更新数据,而不需要加锁)等
- 使用最少线程:线程池的运用等
- 使用协程:Java中没有引入这个概念,可以学习Golang中的协程
-
死锁
线程A持有a锁,线程B持有b锁,线程A想要获取b锁,线程B又想获取a锁,两人相互等待对方释放锁,反而引起死锁。
避免死锁的常见方法:
- 避免一个线程同时获取多个锁
- 避免一个线程在锁内同时占用多个资源,尽量每个锁只占用一个资源
- 使用定时锁,在一定时间内无法获取即放弃
- 锁必须要及时释放
-
资源限制
并发编程时,程序执行速度受限于硬件(如带宽大小、硬盘IO速度)、其他软件资源(数据库连接数量)。
常见的措施有:
- 使用集群方案,应对硬件资源限制
- 使用连接池、线程池等方式,资源复用,应对软件资源限制
- 根据资源情况,调整适合的并发度,减少上下文切换、资源调度