并发编程之上下文切换学习笔记

  • 2019 年 10 月 7 日
  • 筆記

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/u014427391/article/details/101290000

介绍上下文切换之前先介绍一下进程、线程的相关概念,以便于更好地理解上下文切换

进程:在操作系统中的定义是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。在早期的操作系统中,确实是由进程直接执行程序的,所谓程序就是数据、指令及其组织形式的描述。进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度

线程:早期的操作系统程序是由进程执行,现在的操作系统就是由线程执行的,进程是线程的容器,每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。线程拥有自己独立的栈和共享的堆,线程是共享堆,不共享栈的,线程同样由操作系统调度

协程:协程与子例程类似。协程(coroutine)也是一种程序组件。协程和线程一样共享堆,不共享栈。协程由程序员代码控制是否调度,代码控制得好的话,是可以避免无意义的调度的,所以协程是可以用于避免

在java原生的jdk没有提供对应的api,只能通过第三方组件来做,github上有两个是支持的框架,https://github.com/offbynull/coroutines,https://github.com/kilim/kilim

上下文切换(context switch):对于单核CPU来说,在一个时刻只能运行一个线程,对于并行来说,单核cpu也是可以支持多线程执行代码的,CPU是通过给线程分配时间片来解决的,所谓时间片是CPU给每个现场分配的时间,时间片的时间是非常短的,所以执行完成一个时间片后,进行任务切换,切换之前先保存这个任务的状态,以便于下次换回来的时候,可以加载这个任务的状态,所以从保存任务状态到再加载任务的过程称为上下文切换,不仅在线程间可以上下文切换,进程也同样可以

上下文切换测试:

  • Lmbench3 [1] 可 以 测 量 上 下 文 切 换 的 时 长。
  • 使 用 vmstat 可 以 测 量 上 下 文 切 换 的 次 数。

避免上下文切换方法:

多线程的锁竞争会导致上下文切换频繁,所以就可以从这两方面下手,一个方面是锁,就是尽量不用锁;一个方面是线程,不用线程,用其它方法替换

  • 取模分段,将id按照hash算法取模分段,不同线程处理不同端的数据
  • CAS算法,java中的Atomic就是使用CAS算法来更新数据,并没有使用锁
  • 使用协程的方法,在不必要的地方就不调用,避免上下文切换
  • volatitle的应用,volatile关键字可以说是轻量级的锁,volatile关键字是实现线程操作可见性的,可以用于避免上下文切换