多线程系列(二):多线程基础
目录
- 线程的几种状态
- 基础线程
- 前台线程、后台线程
一、线程的几种状态
我们所说的基础线程就是通过Thread类显示创建的线程。可以大体了解一下Thread类相关的成员:
属性:
方法:
线程的5个状态:
1、创建状态(new): 对应 Thread th= new Thread(worker) 时 ,就创建了一个新的线程,仅仅是新建状态,程序还没有运行线程中的代码~
2、就绪状态(Runnable): 对应 th.Start()方法,新建线程在接收到Start()命令之后,调用Run()方法,具体的执行线程。
* 虽然调用了Start()方法,但是线程也不一定即时运行Run()方法。我们知道,多线程是CPU在线程之间来回切换,给出一种多线程的感觉。
如果资源紧张,线程较多,有可能在切换到当前这个线程前,需要等待一段时间。当CPU切换到当前这个线程时,在给定的时间片内运行我们的线程。
3、运行状态(Running): 在切换到当前线程时,在CPU给定的时间片内,真正的运行线程。
4、 阻塞状态(Blocked): 对应 Join()、Sleep()方法。阻塞状态是当前运行线程,暂时中断运行,让出CUP时间片,使得其他正在等待Run()的线程可以真正Run()。
<1> Join()方法:将调用Join()方法的线程,加入到当前线程。使得当前线程挂起,一直到调用Join()方法线程执行完毕。
static void Main(string[] args)
{
System.Threading.Thread childThead = new System.Threading.Thread(ChildThread);
childThead.Start();
//childThead.Join();
Console.WriteLine("Main thread is end");
Console.ReadKey();
}
static void ChildThread()
{
System.Threading.Thread.Sleep(10000);
Console.WriteLine("ChildThread is end");
}
先显示主线程的信息,大约10s后,子线程信息显示,运行结果:
我们解开注释:childThead.Join(); 这里需要理解的是,是将子线程childThead加入到主线程中,主线程挂起,直到子线程childThread执行完毕后,主线程才被唤醒,继续执行。
我们想让谁优先执行,就让我们希望的线程调用Join().所以以上执行的结果是,首先显示子线程信息,完毕后,主线程才显示信息。
<2>Sleep()方法:使得当前线程休眠挂起相应的毫秒数,到了一定的时间就会唤醒自己,继续执行。这里休眠的毫秒数不一定是经过这个时间点就马上唤醒,因为CPU需要在线程间来回切换。
Thread.Sleep(0);在我们遇到长时间运行的线程时,执行一下,会让CPU根据优先级对线程重新排队选择。也许会是当前这个线程,或许是优先级更高的。
<3>Suspend()这个方法不建议使用。
5、 死亡状态(Dead): 对应 Abort()方法。让线程进入死亡状态有两种方式:<1>程序结束后,线程自然就会结束。<2>执行中,抛出异常。
Abort(),就是让线程抛出异常来终止线程。
二、基础线程
1、创建线程
常用有2种方式可以让我们显示创建一个线程
public Thread(ThreadStart start); public Thread(ParameterizedThreadStart start);
参数:ThreadStart(无参无返回值委托) 和 ParameterizedThreadStart(有一个参数无返回值委托) 就是一个委托,如下:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
先创建一个与之(此例为:ThreadStart委托)对应的方法:
static void ChildThread() { System.Threading.Thread.Sleep(10000); Console.WriteLine("ChildThread is end"); }
再创建基础线程:
System.Threading.Thread childThead = new System.Threading.Thread(ChildThread); childThead.Start();
三、前台线程与后台线程
CLR将线程分为两种,即前台线程和后台线程。
线程的状态可以从前台和后台,在生命周期中来回切换。
应用程序主线程以及通过Thread对象显示创建的线程默认为前台线程,线程池的线程默认为后线程。
实例:
System.Threading.Thread backgroundThread = new System.Threading.Thread(BackGroundThreadWorker); if (!backgroundThread.IsBackground) backgroundThread.IsBackground = true; backgroundThread.Start(); var mt = System.Threading.Thread.CurrentThread; mt.Name = "Main"; Console.WriteLine("【Main Thread】: Name—{0};IsBackground—{1};ThreadState—{2}", mt.Name, mt.IsBackground.ToString(), mt.ThreadState.ToString()); Console.WriteLine("Main thread end."); Console.WriteLine(); //主线程没有结束,后台线程继续运行~~ //Console.ReadKey();
与子线程委托对应的方法
public static void BackGroundThreadWorker()
{
var bc = System.Threading.Thread.CurrentThread;
bc.Name = "Background";
Console.WriteLine();
Console.WriteLine("【Background Thread】:Name—{0};IsBackground—{1};ThreadState—{2}", bc.Name, bc.IsBackground.ToString(), bc.ThreadState.ToString());
System.Threading.Thread.Sleep(10000);
Console.WriteLine("Background thread end.");
}
<1>我们运行以上程序,发现主线程(前台线程)的信息显示后,程序直接结束,后台线程也就结束,所以不显示信息。
<2>解开以下注释,使得主线程在等待,所以大约10s后,子线程信息显示。
//主线程没有结束,后台线程继续运行~~
Console.ReadKey();

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)