并发编程的挑战

2019-01-13  本文已影响4人  baiiu

前言

在进行多线程编程时,是希望程序运行的更快,但也会有很多挑战,如上下文切换、死锁、以及受限于硬件和软件的资源限制等问题。
本文会介绍这些挑战 :

什么是上下文切换

CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。

多线程环境中,当一个线程的状态由Runnable转换为非Runnable(Blocked、Waiting、Timed_Waiting)时,相应线程的上下文信息(包括cpu的寄存器和程序计数器在某一时间点的内容等)需要被保存,以便相应线程稍后再次进入Runnable状态时能够在之前的执行进度的基础上继续前进。而一个线程从非Runnable状态进入Runnable状态可能涉及恢复之前保存的上下文信息。这个对线程的上下文进行保存和恢复的过程就被称为上下文切换。

上下文切换会带来额外的开销,这包括对线程上下文信息保存和恢复的开销,对线程进行调度的cpu时间开销以及cpu缓存失效的开销。

线程状态

线程的状态与上下文切换

多线程一定快么

因为线程创建上下文切换(线程来回切换) 的开销,所以不一定多线程就快。

如何减少上下文切换

  1. 无锁并发编程
    多线程竞争锁时,会引起上下文切换。所以多线程处理数据时,可以使用一些办法来避免使用锁。如将数据的ID按照hash算法分段,不同线程处理不同段的数据。
  2. CAS算法
    是现代处理器上提供的高效机器级别的原子指令,这些原子指令以原子方式对内存执行读-写-改操作。Java的Atomic包基于CAS指令来更新数据,不需要加锁。
  3. 使用最少线程
    避免创建不需要的线程。
  4. 协程
    在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换
  5. 可以使用volatile的地方不要使用synchronized
    volatile如果使用得当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。

死锁

指多个线程因抢夺资源而产生的互相等待的现象。
当两个以上的运算单元,双方都在等待对方停止运行,以获取系统资源,但是没有一方提前退出时,就称为死锁。 或所有线程都进入等待状态。

资源限制的挑战

上一篇 下一篇

猜你喜欢

热点阅读