首先多线程是指操作系统在单个进程内支持多个并发执行路径的能力。
什么是线程?
线程是程序中一个更加轻量级的多路径执行实现方式。在系统级别,程序会根据系统为其提供的执行时间以及其他程序需要的执行时间统一调度执行。在程序内部,存在承载着不同任务的一个或多个同时或近乎同时执行的线程。实际上系统本身会管理线程的执行,调度其运行在某个核心上或在其他线程需要执行的时候强制中段该线程的执行。
从技术层面看,线程是一个内核级和应用级数据结构组合,用于管理代码的执行。内核级结构协调事件的调度和可用的核心抢占式调度。应用级结构包括用于存储函数调用的调用堆栈以及需要管理和操作线程的属性与状态的程序结构。
在非并发程序中,只有一个线程的执行。这个线程开始和结束于程序的main函数,并由一个接一个的不同方法或函数来实现程序的全部行为。相比之下,支持并发的程序可以启动一个线程,并按照需求增加线程以创建额外的执行路径。每一条新路径都有独立的自定义启动入口,在程序的main函数中独立运行代码。
避免阻塞
一个线程阻塞后是否会导致整个进程阻塞?
线程系统调用阻塞,在多对1用户级线程模型下,会导致所属进程阻塞。
在1对1/多对多,两种模式下,不会导致该问题。
https://blog.csdn.net/zxc024000/article/details/78972283
使用多线程可以减少程序的响应时间。单线程如果遇到等待或阻塞,将会导致程序不响应鼠标键盘等操作,使用多线程可以解决此问题,增强程序的交互性。
与进程相比,线程的创建和切换开销更小,因为线程共享代码段、数据段等内存空间。
对于进程的并发调度,也就是上下文切换,需要浪费极大地系统资源,例如cpu现场的保护,寄存器,内存地址的信息记录,调度算法的执行,以及进程状态的转换如从运行状态转换到阻塞状态,而且还要把把进程转到相应的队列里面。又因为有些进程只有一部分代码需要别的进程提供一些数据。如果因为这一点的东西需要数据而阻塞,然后要发生强大的进程切换,明显是浪费很多资源。
线程就是把一个进程分成好多部分,每一个部分都是一个线程,这所有的线程,共享进程的资源。当有一个线程需要别的进程提供数据,发生阻塞的时候,只有这个线程发生阻塞,其他的线程或许不需要这些数据也可以运行,因此只需要阻塞这个线程。进行单个线程切换,而整个进程则不需要切换,因此效率更高。单个线程的调度只需要保存一些必要的信息,如寄存器值,栈之子指针内容。线程切换,只需要更改一些寄存器的指针,如PC,pd等寄存器,当然这些是通过硬件实现的,效率是很快的,然后指向当前线程的代码开始地址处,当然对于源代码来说,本质上会经过编译程序和链接程序最终编程目标代码存放在内存之中的某一空白的内存地址处,并同时记录该内存地址的首地址,这些都是硬件级别的调用,只要要硬件的一些寄存器之类的东西转换一下就可以。速度相当快。并不需要什么进程调度算法,这些很慢的调度。因此引入线程,后系统的并发度会更高。
单核CPU上运行的多线程程序, 同一时间只能一个线程在跑, 系统切换线程, 系统给每个线程分配时间片来执行, 每个时间片大概10ms左右, 看起来像是同时跑, 但实际上是每个线程跑一点点就换到其它线程继续跑 效率不会有提高的 切换线程会增加开销
在单核CPU的时候,不推荐使用多线程。
在单核系统中如果某个线程获取了锁,那么这个线程将获取CPU的运行时间,其他线程将被阻塞。但CPU始终处于运行状态,影响计算时间的其实只是加锁和解锁的时间。并不会发生CPU空闲的现象。
但多核系统中情况发生了本质的变换,如果线程A和B使用同一把锁,但运行在不同的CPU上,如果A得到了锁,那么A线程所在CPU则处于运行状态,线程B处于阻塞状态,B线程所在CPU则处于空闲状态。我们浪费了一个CPU的运算时间。
图示:
多核多线程并行需要注意的问题:
1、线程过多:如果系统上的线程数量远远超过核心的数量,那么就会导致频繁的上下文切换,进而降低性能,如缓存污染。通常支持超线程的多核处理器能够使用的线程数最多是物理核心数的2倍,再增加就有可能降低程序的性能;
2、数据竞争:当多个线程读写同一共享数据时,便会产生竞争,需要同步,同步通常会导致线程之间的相互等待,潜在的降低了性能;另一方面,如果不使用同步程序可能无法并行。
3、死锁:线程发生死锁时,处理器都在操作(一直询问需要的资源是否可用),但是线程都在相互等待其他线程释放资源,处于僵持状态。
4、饿死:当一个或多个线程永远没有机会调度到处理器上执行,而陷入永远的等待的状态。
5、伪共享:当多个线程读写的数据映射到同一条缓存线上时,如果一个线程更改了数据,那么其他线程对该数据的缓存就要被失效,,如果频繁地更改数据,硬件就需要不停的更新缓存线,这使性能从独享缓存的水平降低到共享缓存或内存的水平。
计算性能提升的比例 阿姆达尔定律: (Amdahl)
速度提升比例 = 1/[(1-P)+(P/N)],其中P是可并行任务的比例,N是CPU核心数量
多线程的好处:
使用线程可以把占据时间长的程序中的任务放到后台去处理
用户界面更加吸引人,这样比如用户点击了一个按钮去触发某件事件的处理,可以弹出一个进度条来显示处理的进度
程序的运行效率可能会提高
在一些等待的任务实现上如用户输入,文件读取和网络收发数据等,线程就比较有用了.
多线程的缺点:
如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换.
更多的线程需要更多的内存空间
线程中止需要考虑对程序运行的影响.
通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生
IOS多线程
https://www.jianshu.com/p/7c347999332b
Android多线程
https://www.jianshu.com/p/c7b16c3c4625