环境:

  • window 10
  • .NetFramework 4.7
  • vs2019 16.4.5

一、线程的状态

线程的状态可以从枚举ThreadState中查看到:

public enum ThreadState
{Running = 0x0,StopRequested = 0x1,SuspendRequested = 0x2,Background = 0x4,Unstarted = 0x8,Stopped = 0x10,WaitSleepJoin = 0x20,Suspended = 0x40,AbortRequested = 0x80,Aborted = 0x100
}

我们先抛开Background不谈,说一下其他的九种状态:

  • Unstarted :
    当我们var thread = new Thread(()=>{})执行后,这个线程就被创建了,此时它并不会被cpu执行,它的状态为:Unstarted
  • Running :
    当我们调用thread.Start()方法后,这个线程就安排给cpu调用了,此时它的状态为Running
  • Stopped、StopRequested :
    当我们创建的线程正常执行后,它没代码执行了,也就是死掉了,此时它的状态为Stopped ,注意:这里说的是正常执行完毕,并不是被强制终止(thead.Abort())。至于StopRequested,从名字可以看出它是处于Stopped状态之前的,可能是速度太快,我调试的时候并没有捕获到。最后,线程结束后不能重新发起
  • WaitSleepJoin :
    这种状态也称之为休眠状态,由thread.Join()或Thread.Sleep()引发,前者是主线程调用子线程的Join方法导致主线程阻塞(直到子线程执行完毕才能解除阻塞)并切换到WaitSleepJoin状态,后者是子线程内部调用Sleep方法导致子线程休眠并切换到WaitSleepJoin状态。从这个方法的名字中也可以看到它主要是由Join和Sleep方法引起的线程休眠(程序锁也会导致休眠),而解除这种状态的方法是thread.Interrupt()。注意:thread.Interrupt()会导致线程在阻塞处抛出异常,注意捕捉。
  • Suspended、SuspendRequested:(挂起操作不被建议使用,标记为废弃的api,.netcore中不支持Suspend/Resume方法的调用
    线程被挂起时的状态,由thread.Suspend()引发。注意:进程的挂起和休眠不是一个意思,线程的休眠必须指定休眠的时间,时间一到就自动解除休眠,而挂起则不然,它必须被其他线程解除挂起才行,也可以这样说:线程的休眠是线程本身根据需要引发的,而挂起则是由管理者决定的。当一个线程处于WaitSleepJoin状态时管理者仍然可以将这个线程标记为挂起,只不过这个由于线程已经自己休眠了,所以就暂时安排个SuspendRequested状态,等它的休眠期已过就立刻打上Suspend状态。还有一个重要的地方,线程被挂起时会抛出异常,如果没有处理线程就会死掉,如果处理了,代码的执行位置就会改变,这一点和休眠是很不同的。最后,处于Suspend状态的线程只能由管理者调用Resume()方法解除挂起
  • Aborted、AbortRequested(结束线程最好的方法是通过信号灯让线程自己中断,而不是强制Abort:C# Thread.Abort方法真的让线程停止了吗?,.netcore中不支持Abort方法的调用)
    线程被终止状态,这个和Stopped不同,Stopped是正常执行完毕,而Aborted是被强制终止并抛出异常。


注意:
不要使用Suspend和Resume方法来同步线程的活动。当你Suspend线程时,您无法知道线程正在执行什么代码。如果在安全权限评估期间线程持有锁时挂起线程,则AppDomain中的其他线程可能会被阻塞。如果线程在执行类构造函数时Suspend,则试图使用该类的AppDomain中的其他线程将被阻塞。死锁很容易发生。

二、测试代码

2.1 测试Join()方法阻塞主线程

using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Threading;
namespace TestDI
{class Program{public static void Main(string[] args){Test6();Console.WriteLine("ok");Console.ReadLine();}private static void Test6(){var threadMain = Thread.CurrentThread;var thread = new Thread(() =>{Thread.Sleep(2000);for (int i = 0; i < 10000; i++){File.AppendAllText("d:\\temp.txt", i + "\r\n");}//由于这个线程被主线程执行thread.Join(),从而导致主线程被阻塞,所以主线程状态为:WaitSleepJoinConsole.WriteLine("主线程状态:" + threadMain.ThreadState);});//线程thread刚被创建,还未启动,状态为:UnstartedConsole.WriteLine(thread.ThreadState);thread.Start();//线程thread启动后,线程的状态变为:RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(1000);//线程thread此时执行到Thread.Sleep(2000);,状态为:WaitSleepJoinConsole.WriteLine(thread.ThreadState);thread.Join();//线程被执行了Join导致此处代码被阻塞,这里获取的状态肯定是StoppedConsole.WriteLine(thread.ThreadState);//主线程状态也从WaitSleepJoin改为RunningConsole.WriteLine("主线程:" + threadMain.ThreadState);}}
}

输出效果:

2.2 测试Abort()方法终止线程

.netcore不支持Abort,而且线程的正确终止方法应该是通过信号灯让线程本身结束,而不是强制结束,因为你无法预测线程正在做什么!

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace ConsoleApp1
{class Program{static void Main(string[] args){Test5();Console.WriteLine("ok");Console.ReadLine();}private static void Test5(){var thread = new Thread(() =>{try{Thread.Sleep(2000);}catch (Exception ex){Console.WriteLine("异常:" + ex.Message);}for (int i = 0; i < 10000; i++){File.AppendAllText("d:\\temp.txt", i + "\r\n");}});//线程thread刚被创建,还未启动,状态为:UnstartedConsole.WriteLine(thread.ThreadState);thread.Start();//线程thread启动后,线程的状态变为:RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(1000);//线程thread此时执行了Thread.Sleep(2000);,状态为:WaitSleepJoinConsole.WriteLine(thread.ThreadState);thread.Abort();Thread.Sleep(500);//线程thread已经Aborted了Console.WriteLine(thread.ThreadState);}}
}

输出效果:

2.3 测试线程的挂起和休眠的叠加状态: 先从休眠中唤醒再解除挂起

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace ConsoleApp1
{class Program{static void Main(string[] args){Test4();Console.WriteLine("ok");Console.ReadLine();}private static void Test4(){var thread = new Thread(() =>{try{Thread.Sleep(2000);}catch (Exception ex){Console.WriteLine("异常:" + ex.Message);}for (int i = 0; i < 1000; i++){File.AppendAllText("d:\\temp.txt", i + "\r\n");}});//线程thread刚被创建,还未启动,状态为:UnstartedConsole.WriteLine(thread.ThreadState);thread.Start();//线程thread启动后,线程的状态变为:RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(1000);//线程thread此时执行了Thread.Sleep(2000);,状态为:WaitSleepJoinConsole.WriteLine(thread.ThreadState);thread.Suspend();Thread.Sleep(500);//线程thread被执行Suspend(),状态为SuspendRequested, WaitSleepJoin,并引发异常Console.WriteLine(thread.ThreadState);if (thread.ThreadState == (ThreadState.SuspendRequested | ThreadState.WaitSleepJoin)){Console.WriteLine("ThreadState.SuspendRequested | ThreadState.WaitSleepJoin\t" + true);}Thread.Sleep(1500);//线程thread此时已从Sleep中苏醒,状态为SuspendConsole.WriteLine(thread.ThreadState);thread.Resume();Thread.Sleep(500);//线程thread被执行Resume(),状态为RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(10000);//线程thread已经执行完毕,状态为StoppedConsole.WriteLine(thread.ThreadState);}}
}

输出效果:

2.4 测试线程的挂起和休眠的叠加状态: 先解除挂起再从休眠中唤醒

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace ConsoleApp1
{class Program{static void Main(string[] args){Test3();Console.WriteLine("ok");Console.ReadLine();}/// <summary>/// 测试线程状态Unstarted->Running->WaitSleepJoin->SuspendRequested, WaitSleepJoin->WaitSleepJoin->Running->Stopped/// 线程先睡眠再挂起,然后解除挂起,然后自动唤醒/// .netcore不支持Suspend/Resume,而且这两个方法已经标记为废弃的api/// </summary>private static void Test3(){var thread = new Thread(() =>{try{Thread.Sleep(2000);}catch (Exception ex){Console.WriteLine("异常:" + ex.Message);}for (int i = 0; i < 1000; i++){File.AppendAllText("d:\\temp.txt", i + "\r\n");}});//线程thread刚被创建,还未启动,状态为:UnstartedConsole.WriteLine(thread.ThreadState);thread.Start();//线程thread启动后,线程的状态变为:RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(1000);//线程thread此时执行了Thread.Sleep(2000);,状态为:WaitSleepJoinConsole.WriteLine(thread.ThreadState);thread.Suspend();Thread.Sleep(500);//线程thread被执行Suspend(),状态为SuspendRequested, WaitSleepJoinConsole.WriteLine(thread.ThreadState);thread.Resume();Thread.Sleep(500);//线程thread被执行Resume(),状态为WaitSleepJoinConsole.WriteLine(thread.ThreadState);Thread.Sleep(2000);//线程thread已经从Sleep中苏醒,状态为RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(8000);//线程thread已经执行完毕,状态为StoppedConsole.WriteLine(thread.ThreadState);}}
}

输出效果:

2.5 测试线程休眠后使用Interrupt方法唤醒

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace ConsoleApp1
{class Program{static void Main(string[] args){Test2();Console.WriteLine("ok");Console.ReadLine();}/// <summary>/// 测试线程状态Unstarted->Running->WaitSleepJoin->Running->Stopped/// 休眠后使用Interrupt方法唤醒/// </summary>private static void Test2(){var thread = new Thread(() =>{try{Thread.Sleep(2000);}catch (Exception ex){Console.WriteLine(ex.Message);}for (int i = 0; i < 1000; i++){File.AppendAllText("d:\\temp.txt", i + "\r\n");}});//线程thread刚被创建,还未启动,状态为:UnstartedConsole.WriteLine(thread.ThreadState);thread.Start();//线程thread启动后,线程的状态变为:RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(1000);//线程thread此时执行了Thread.Sleep(2000);,状态为:WaitSleepJoinConsole.WriteLine(thread.ThreadState);thread.Interrupt();Thread.Sleep(100);//线程thread被执行Interrupt(),状态为RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(10 * 1000);//线程thread已经执行完毕,状态为StoppedConsole.WriteLine(thread.ThreadState);}}
}

输出效果:

2.6 测试线程休眠后自动唤醒

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace ConsoleApp1
{class Program{static void Main(string[] args){Test1();Console.WriteLine("ok");Console.ReadLine();}/// <summary>/// 测试线程状态Unstarted->Running->WaitSleepJoin->Running->Stopped/// 休眠到期后自动唤醒/// </summary>private static void Test1(){var thread = new Thread(() =>{Thread.Sleep(2000);for (int i = 0; i < 1000; i++){File.AppendAllText("d:\\temp.txt", i + "\r\n");}});//线程thread刚被创建,还未启动,状态为:UnstartedConsole.WriteLine(thread.ThreadState);thread.Start();//线程thread启动后,线程的状态变为:RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(1000);//线程thread此时执行了Thread.Sleep(2000);,状态为:WaitSleepJoinConsole.WriteLine(thread.ThreadState);Thread.Sleep(1500);//线程thread此时正在运行,状态为RunningConsole.WriteLine(thread.ThreadState);Thread.Sleep(8000);//线程thread此时已经运行完毕,状态为StoppedConsole.WriteLine(thread.ThreadState);}}
}

输出效果:

c#: 线程状态和管理之线程的休眠、挂起和中断相关推荐

  1. 线程状态,优先级,守护线程基础详解

    线程状态,优先级,守护线程基础详解 线程状态 停止线程 线程休眠 线程礼让 线程强制执行 线程状态检测 线程的优先级 守护线程 线程同步 线程状态 创建状态(new 之后就是创建状态 就绪状态(调用s ...

  2. java 线程状态 jstack_jstack查看jvm线程状态

    有些时候我们需要查看下jvm中的线程执行情况,比如,发现服务器的CPU的负载突然增 高了.出现了死锁.死循环等,我们该如何分析呢? 由于程序是正常运行的,没有任何的输出,从日志方面也看不出什么问题,所 ...

  3. Java 线程实例二(终止线程、生产者/消费者问题、获取线程状态、获取所有线程、查看线程优先级、中断线程)

    终止线程 Java中原来在Thread中提供了stop()方法来终止线程,但这个方法是不安全的,所以一般不建议使用. 本文向大家介绍使用interrupt方法中断线程. 使用interrupt方法来终 ...

  4. java 线程状态_关于JAVA线程状态

    最近在复习java基础知识,在看到java多线程知识的时候偶然搜到一篇csdn上的博客. 这篇博客上弄了一张描述java线程状态转换的图,如下 看到的第一眼直觉上告诉这图我哪里不太对,于是我就去了的相 ...

  5. 多线程——线程实现、线程状态、线程同步、线程通信、线程池

    多线程 一.线程 1.普通方法调用和多线程 2.程序.进行.线程 二.线程创建 1.继承Thread类 2.实现Runable接口 3.实现Callable接口 4.静态代理模式 5.Lamda表达式 ...

  6. 面试必备,Java线程状态之细节回顾

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 来源:https://dwz.cn/vYqjShos Java线程有6种状态 在某个给定时间点 ...

  7. Java线程状态及 wait、sleep、join、interrupt、yield等的区别

    Java中的线程状态(详见Java线程状态及转换-MarchOn): wait:Object类的实例方法,释放CPU执行权,进入等待状态,直到  被中断.被拥有该对象锁的线程唤醒(notify或not ...

  8. 【并发编程】线程中的Sleep、Yield、Join等api方法方法线程状态转换

    在上两篇中我们学习线程的概念和如何创建线程,在本篇中我们学习一些线程的方法和线程的状态. 方法 Sleep:线程睡眠 线程休眠指的是让线程暂缓执行以一下,等到了预计时间之后再恢复执行参数是毫秒.当线程 ...

  9. java 线程状态_JAVA线程漫谈:线程状态与状态转换解析

    线程使用方式 JDK线程的顶层抽象是Runnable接口,本质上,线程相关的类都是基于Runnable和Thread实现类实现. JDK API级别有不同的创建线程的方式,但本质是还是基于Runnab ...

最新文章

  1. Matlab心得及学习方法(不断更新)
  2. 网站的高性能架构---存储性能优化
  3. PHP自动加载__autoload的工作机制
  4. 【实验】配置DHCP和NAT访问Internet公网案例
  5. boost::geometry::index::detail::segment_intersection用法的测试程序
  6. onnx模型推理(python)
  7. 将数据转化成字符串时:用字符串的链接 还是 StringBuilder
  8. 2原理图_pcb板设计电路原理图步骤和方法
  9. 8中间件,csrf跨站请求伪造,auth模块
  10. 一文搞懂MySQL-8.0 redo优化
  11. html view设置全屏,uni-app 如何设置web-view 不全屏,不自动铺满,动态控制web-view的高度...
  12. Python软件包的安装(3种方法)
  13. 利用OD去软件弹窗广告教程-[WinRAR_3.9]为例
  14. Ubuntu18.04美化桌面
  15. 头歌平台(EduCoder)————数据挖掘算法原理与实践:决策树
  16. 信息技术服务风险评估
  17. Anroid 逆向工具
  18. HAProxy 简介及配置文件详解
  19. oracle成本cbo,基于成本的优化器(CBO)
  20. 阿里巴巴YunOS在CES上展示IoT生态

热门文章

  1. 【文献调研】三相DLMP的motivation调研
  2. Mysql窗口函数 (知识点梳理+题目解析+面试实战)(四万字长文,一文读懂,建议收藏后食用)
  3. µTorrent中只使用ipv6连接
  4. ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  5. Dynamics AX2012 SSRS errors:For more information about this error navigate...
  6. 移动端开发-响应式页面
  7. C#支持正负数的数字正则验证表达式
  8. php 调用 C++
  9. expdp与impdp导出导入特定表
  10. 拼多多商家想做好推广一定不能这么做!