多线程相关知识点

一.什么是多线程

做后台开发的经常会用到一种技术叫多线程,那什么是多线程呢,以及我们什么时候会用到它呢?那我们就记录一下相关知识点,如果错误之处希望可以帮忙指正。

1.多线程的概念

线程 被定义为程序的执行路径,它是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程。

举个例子:迅雷是一个进程,我们使用迅雷下载文件时,可能存在多个文件同时下载的情况,那么此时就涉及到了多线程技术,显而易见,进程和线程的关系是一对多的关系。

先了解一个概念:抢占式调度模式  即优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性)执行,Java使用的为抢占式调度

我们平时使用电脑时,可能同时在使用TX视频看小电影,还在用某音乐听音乐,还在TB上剁手,看似这些软件在同时运行着,

实际上,CPU(中央处理器)在使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行。所以我们现在追求多核而且更好的处理器。

其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。

听起来好像多线程百利而无一害,但实际时这样吗?对比一下就知道了。

多线程的优点:
(1)多线程技术使程序的响应速度更快 ,因为用户界面可以在进行其它工作的同时一直处于活动状态;
(2)多线程可以提高CPU的利用率,因为当一个线程处于等待状态的时候,CPU会去执行另外的线程;
(3)占用大量处理时间的任务可以定期将处理器时间让给其它任务;
(4)可以随时停止任务;
(5)可以分别设置各个任务的优先级以及可以合理的释放资源以优化性能。

多线程缺点:
(1)等候使用共享资源时造成程序的运行速度变慢(资源共享问题),这些共享资源主要是独占性的资源 ,如写文件。
(2)对线程进行管理要求额外的 CPU开销,线程的使用会给系统带来上下文切换的额外负担。
(3)线程的死锁。即较长时间的等待或资源竞争以及死锁等多线程症状(涉及到线程安全)。
(4)对同一资源同时读或写。当多个线程需要对同一资源进行写操作时,后一个线程往往会修改掉前一个线程存放的数据,从而使前一个线程的参数被修改;另外 ,当同一资源的读写操作是非原子性时,在不同的机器上,中断时间的不确定性,会导致数据在一个线程内的操作产生错误,从而产生莫名其妙的错误,而这种错误是开发者无法预知的。
 

2.多线程和异步

有些小伙伴看到上面优点提到可以用多线程处理一些耗时操作,心想我用异步不是也可以完成吗?其实两者是不一样的。

同步:也可以理解为单线程,是从上下顺序执行,比如我要导出一个文件,其中的计算可能需要花费一点时间,而我必须要等它计算完写到文件中才能导出。

异步:导出逻辑采用异步执行的方式,即后台执行此段逻辑,执行到什么程度我不管,我完全可以先做别的事情,等导出方法执行完毕自动会给我返回。

多线程:我把导出逻辑放到Thread1中,执行到此线程方法时,我先跳过,当其他事情都处理好我再执行这段耗时操作即可。此时我只要处理好线程的执行顺序即可。

3.多线程应用场景

有时候看到一些博文写的采用多线程可以缩短执行时间,我就有点疑问,要知道多线程并不是同时执行的,只是为了提高CPU的利用效率和合理安排线程的执行顺序,按道理是采用多线程会比多线程增加一个切换线程的环节,时间应该变长才对,不应该缩短啊。其实这里我有一个误区,以上是针对单核CPU说的。

再普及两个概念。

并发:当存在多个线程时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。
并行:当系统有一个以上CPU时,则线程的操作有可能非并发,当其中一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

一、高并发

系统接受实现多用户多请求的高并发时,可以通过多线程来实现。

二、线程后台处理大任务

一个程序是线性执行的。如果程序执行到要花大量时间处理的任务时,那主程序就得等待其执行完才能继续执行下面的。那用户就不得不等待它执行完。

这时候可以开线程把花大量时间处理的任务放在线程处理,这样线程在后台处理时,主程序也可以继续执行下去,用户就不需要等待。线程执行完后执行回调函数。

三、大任务

大任务处理起来比较耗时,这时候可以起到多个线程并行加快处理(例如:分片上传)。

连续的操作,需要花费忍无可忍的过长时间才可能完成
并行计算,为了等待网络、文件系统、用户或其他I/O响应而耗费大量的执行时间
所以说,在动手之前,先保证自己的应用程序中是否出现了以上3种情形。

二.线程安全

1.线程生命周期

线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。

下面列出了线程生命周期中的各种状态:

  • 未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。
  • 就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
  • 不可运行状态:下面的几种情况下线程是不可运行的:
    • 已经调用 Sleep 方法
    • 已经调用 Wait 方法
    • 通过 I/O 操作阻塞
  • 死亡状态:当线程已完成执行或已中止时的状况。

2.线程安全

原子性:一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行
可见性:多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他线程可以立即看到修改的结果。
有序性:即程序的执行顺序按照代码的先后顺序来执行。

C#如何保证线程安全

为了更清晰的看出实例和防止篇幅过长,举例放在下篇博客中。

https://blog.csdn.net/qq_36730649/article/details/105554359

三.线程池

我们已经知道了使用多线程可以解决很多问题,但是如果乱创建线程的代价也是很大的。使用多线程我们要注意以下问题

1、线程开的越多,内存占用越大

2、协调和管理代码的难度加大,需要CPU时间跟踪线程

3、线程之间对资源的共享可能会产生可不遇知的问题

为了更好地管理线程,我们需要借助线程池这个工具。

1.什么是线程池

百度百科:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。

线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。

如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。

微软官网:许多应用程序创建大量处于睡眠状态,等待事件发生的线程。还有许多线程可能会进入休眠状态,这些线程只是为了定期唤醒以轮询更改或更新的状态信息。 线程池,使您可以通过由系统管理的工作线程池来更有效地使用线程。

其中, .NET Framework的ThreadPool类提供一个线程池,该线程池可用于执行任务、发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。线程池其实就是一个存放线程对象的“池子(pool)”,他提供了一些基本方法,如:设置pool中最小/最大线程数量、把要执行的方法排入队列等等。

ThreadPool是一个静态类,因此可以直接使用,不用创建对象。
 

2.C#如何使用线程池

为了更清晰的看出实例和防止篇幅过长,举例放在下篇博客中。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值