并发编程的挑战

本文主要介绍几种并发编程可能会遇到的挑战,及其解决方案。

1. 上下文切换

cpu通过时间片分配算法来循环执行线程,当前线程时间片用完后就会切换到下一线程。但是在切换之前,必须先保存当前线程的上下文,然后再加载下一个线程的上下文,称为上下文的切换。频繁的上下文切换会导致程序的执行效率低下。

解决方案:减少上下文切换的方法有无锁并发编程,CAS算法,使用最少线程,协程

  • 无锁并发编程:多线程在竞争锁时会引起上下文的切换。所以多线程在处理数据时,可以用一些方法来避免使用锁,比如讲数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。
  • CAS算法:java的原子并发包使用的是CAS算法来更新数据,不需要加锁。
  • 使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多线程,这就会导致大量线程都处于等待状态。
  • 协程:在单线程里实现多任务的调度,并在单线程里维持多任务间的切换。

2. 死锁

死锁产生的一种情况就是两个线程之间互相等待对方释放锁。
解决方案:

  • 尽量避免一个线程同时获取多个锁
  • 避免线程在锁内部同时占用多个资源,尽量保证一个锁只占用一个资源
  • 尝试使用定时锁,使用lock.tryLock(timeout)来代替内部锁机制
  • 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

3. 资源限制的挑战

资源限制是指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源。例如服务器的带宽只有2Mb/s,某个资源的下载速度是1Mb/s,系统启动10线程下载资源,下载速度并不会达到10Mb/s。硬件资源的限制有带宽的上传/下载速度,硬盘读写速度和cpu的处理速度等,软件资源的限制有数据库连接数和socket连接数等。
解决方案:

  • 对于硬件资源的限制,可以考虑使用集群并行执行程序
  • 对于软件资源的限制,可以考虑使用资源池将资源复用,比如数据库连接池等。