返回顶部
首页 > 资讯 > 精选 >C#线程的创建和生命周期实例分析
  • 118
分享到

C#线程的创建和生命周期实例分析

2023-06-29 04:06:17 118人浏览 安东尼
摘要

本篇内容介绍了“C#线程的创建和生命周期实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1,获取当前线程信息Thread.Curren

本篇内容介绍了“C#线程的创建和生命周期实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1,获取当前线程信息

Thread.CurrentThread 是一个 静态的 Thread 类,Thread 的CurrentThread 属性,可以获取到当前运行线程的一些信息,其定义如下:

public static System.Threading.Thread CurrentThread { get; }

Thread 类有很多属性和方法,这里就不列举了,后面的学习会慢慢熟悉更多 api 和深入了解使用。

这里有一个简单的示例:

        static void Main(string[] args)        {            Thread thread = new Thread(OneTest);            thread.Name = "Test";            thread.Start();            Console.ReadKey();        }        public static void OneTest()        {            Thread thisTHread = Thread.CurrentThread;            Console.WriteLine("线程标识:" + thisTHread.Name);            Console.WriteLine("当前地域:" + thisTHread.CurrentCulture.Name);  // 当前地域            Console.WriteLine("线程执行状态:" + thisTHread.IsAlive);            Console.WriteLine("是否为后台线程:" + thisTHread.IsBackground);            Console.WriteLine("是否为线程池线程"+thisTHread.IsThreadPoolThread);        }

输出

线程标识:Test当前地域:zh-CN线程执行状态:True是否为后台线程:False是否为线程池线程False

2,管理线程状态

一般认为,线程有五种状态:

新建(new 对象) 、就绪(等待CPU调度)、运行(CPU正在运行)、阻塞(等待阻塞、同步阻塞等)、死亡(对象释放)。

C#线程的创建和生命周期实例分析

理论的东西不说太多,直接撸代码。

2.1 启动与参数传递

新建线程简直滚瓜烂熟,无非 new 一下,然后 Start()

Thread thread = new Thread();

Thread 的构造函数有四个:

public Thread(ParameterizedThreadStart start);public Thread(ThreadStart start);public Thread(ParameterizedThreadStart start, int maxStackSize);public Thread(ThreadStart start, int maxStackSize);

我们以启动新的线程时传递参数来举例,使用这四个构造函数呢?

2.1.1 ParameterizedThreadStart

ParameterizedThreadStart 是一个委托,构造函数传递的参数为需要执行的方法,然后在 Start 方法中传递参数。

需要注意的是,传递的参数类型为 object,而且只能传递一个。

代码示例如下:

        static void Main(string[] args)        {            string myParam = "abcdef";            ParameterizedThreadStart parameterized = new ParameterizedThreadStart(OneTest);            Thread thread = new Thread(parameterized);            thread.Start(myParam);            Console.ReadKey();        }        public static void OneTest(object obj)        {            string str = obj as string;            if (string.IsNullOrEmpty(str))                return;            Console.WriteLine("新的线程已经启动");            Console.WriteLine(str);        }
2.1.2 使用静态变量或类成员变量

此种方法不需要作为参数传递,各个线程共享堆栈。

优点是不需要装箱拆箱,多线程可以共享空间;缺点是变量是大家都可以访问,此种方式在多线程竞价时,可能会导致多种问题(可以加解决)。

下面使用两个变量实现数据传递:

    class Program    {        private string A = "成员变量";        public static string B = "静态变量";        static void Main(string[] args)        {            // 创建一个类            Program p = new Program();            Thread thread1 = new Thread(p.OneTest1);            thread1.Name = "Test1";            thread1.Start();            Thread thread2 = new Thread(OneTest2);            thread2.Name = "Test2";            thread2.Start();            Console.ReadKey();        }        public void OneTest1()        {            Console.WriteLine("新的线程已经启动");            Console.WriteLine(A);       // 本身对象的其它成员        }        public static void OneTest2()        {            Console.WriteLine("新的线程已经启动");            Console.WriteLine(B);       // 全局静态变量        }    }
2.1.3 委托与Lambda

原理是 Thread 的构造函数 public Thread(ThreadStart start);ThreadStart 是一个委托,其定义如下

public delegate void ThreadStart();

使用委托的话,可以这样写

        static void Main(string[] args)        {            System.Threading.ThreadStart start = DelegateThread;            Thread thread = new Thread(start);            thread.Name = "Test";            thread.Start();            Console.ReadKey();        }        public static void DelegateThread()        {            OneTest("a", "b", 666, new Program());        }        public static void OneTest(string a, string b, int c, Program p)        {            Console.WriteLine("新的线程已经启动");        }

有那么一点点麻烦,不过我们可以使用 Lambda 快速实现。

使用 Lambda 示例如下:

        static void Main(string[] args)        {            Thread thread = new Thread(() =>            {                OneTest("a", "b", 666, new Program());            });            thread.Name = "Test";            thread.Start();                        Console.ReadKey();        }        public static void OneTest(string a, string b, int c, Program p)        {            Console.WriteLine("新的线程已经启动");        }

提示:如果需要处理的算法比较简单的话,可以直接写进委托中,不需要另外写方法啦。

可以看到,C# 是多么的方便。

2.2 暂停与阻塞

Thread.Sleep() 方法可以将当前线程挂起一段时间,Thread.Join() 方法可以阻塞当前线程一直等待另一个线程运行至结束。

在等待线程 Sleep() 或 Join() 的过程中,线程是阻塞的(Blocket)。

    阻塞的定义:当线程由于特点原因暂停执行,那么它就是阻塞的。 
    如果线程处于阻塞状态,线程就会交出他的 CPU 时间片,并且不会消耗 CPU 时间,直至阻塞结束。 
    阻塞会发生上下文切换。

代码示例如下:

        static void Main(string[] args)        {            Thread thread = new Thread(OneTest);            thread.Name = "小弟弟";            Console.WriteLine($"{DateTime.Now}:大家在吃饭,吃完饭后要带小弟弟逛街");            Console.WriteLine("吃完饭了");            Console.WriteLine($"{DateTime.Now}:小弟弟开始玩游戏");            thread.Start();            // 化妆 5 s            Console.WriteLine("不管他,大姐姐化妆先"); Thread.Sleep(TimeSpan.FromSeconds(5));            Console.WriteLine($"{DateTime.Now}:化完妆,等小弟弟打完游戏");            thread.Join();            Console.WriteLine("打完游戏了嘛?" + (!thread.IsAlive ? "true" : "false"));            Console.WriteLine($"{DateTime.Now}:走,逛街去");            Console.ReadKey();        }        public static void OneTest()        {            Console.WriteLine(Thread.CurrentThread.Name + "开始打游戏");            for (int i = 0; i < 10; i++)            {                Console.WriteLine($"{DateTime.Now}:第几局:" + i);                Thread.Sleep(TimeSpan.FromSeconds(2));      // 休眠 2 秒            }            Console.WriteLine(Thread.CurrentThread.Name + "打完了");        }

Join() 也可以实现简单的线程同步,即一个线程等待另一个线程完成。

2.3 线程状态

ThreadState 是一个枚举,记录了线程的状态,我们可以从中判断线程的生命周期和健康情况。

其枚举如下:

枚举说明
Initialized0此状态指示线程已初始化但尚未启动。
Ready1此状态指示线程因无可用的处理器而等待使用处理器。 线程准备在下一个可用的处理器上运行。
Running2此状态指示线程当前正在使用处理器。
Standby3此状态指示线程将要使用处理器。 一次只能有一个线程处于此状态。
Terminated4此状态指示线程已完成执行并已退出。
Transition6此状态指示线程在可以执行前等待处理器之外的资源。 例如,它可能正在等待其执行堆栈从磁盘中分页。
Unknown7线程的状态未知。
Wait5此状态指示线程尚未准备好使用处理器,因为它正在等待外围操作完成或等待资源释放。 当线程就绪后,将对其进行重排。

但是里面有很多枚举类型是没有用处的,我们可以使用一个这样的方法来获取更加有用的信息:

        public static ThreadState GetThreadState(ThreadState ts)        {            return ts & (ThreadState.Unstarted |                ThreadState.WaitSleepJoin |                ThreadState.Stopped);        }

根据 2.2 中的示例,我们修改一下 Main 中的方法:

        static void Main(string[] args)        {            Thread thread = new Thread(OneTest);            thread.Name = "小弟弟";            Console.WriteLine($"{DateTime.Now}:大家在吃饭,吃完饭后要带小弟弟逛街");            Console.WriteLine("吃完饭了");            Console.WriteLine($"{DateTime.Now}:小弟弟开始玩游戏");            Console.WriteLine("弟弟在干嘛?(线程状态):" + Enum.GetName(typeof(ThreadState), GetThreadState(thread.ThreadState)));            thread.Start();            Console.WriteLine("弟弟在干嘛?(线程状态):" + Enum.GetName(typeof(ThreadState), GetThreadState(thread.ThreadState)));            // 化妆 5 s            Console.WriteLine("不管他,大姐姐化妆先"); Thread.Sleep(TimeSpan.FromSeconds(5));            Console.WriteLine("弟弟在干嘛?(线程状态):" + Enum.GetName(typeof(ThreadState), GetThreadState(thread.ThreadState)));            Console.WriteLine($"{DateTime.Now}:化完妆,等小弟弟打完游戏");            thread.Join();            Console.WriteLine("弟弟在干嘛?(线程状态):" + Enum.GetName(typeof(ThreadState), GetThreadState(thread.ThreadState)));            Console.WriteLine("打完游戏了嘛?" + (!thread.IsAlive ? "true" : "false"));            Console.WriteLine($"{DateTime.Now}:走,逛街去");            Console.ReadKey();        }

代码看着比较乱,请复制到项目中运行一下。

输出示例:

2020/4/11 11:01:48:大家在吃饭,吃完饭后要带小弟弟逛街吃完饭了2020/4/11 11:01:48:小弟弟开始玩游戏弟弟在干嘛?(线程状态):Unstarted弟弟在干嘛?(线程状态):Running不管他,大姐姐化妆先小弟弟开始打游戏2020/4/11 11:01:48:第几局:02020/4/11 11:01:50:第几局:12020/4/11 11:01:52:第几局:2弟弟在干嘛?(线程状态):WaitSleepJoin2020/4/11 11:01:53:化完妆,等小弟弟打完游戏2020/4/11 11:01:54:第几局:32020/4/11 11:01:56:第几局:42020/4/11 11:01:58:第几局:52020/4/11 11:02:00:第几局:62020/4/11 11:02:02:第几局:72020/4/11 11:02:04:第几局:82020/4/11 11:02:06:第几局:9小弟弟打完了弟弟在干嘛?(线程状态):Stopped打完游戏了嘛?true2020/4/11 11:02:08:走,逛街去

可以看到 UnstartedWaitSleepJoinRunningStopped四种状态,即未开始(就绪)、阻塞、运行中、死亡。

2.4 终止

.Abort() 方法不能在 .net core 上使用,不然会出现 System.PlatfORMNotSupportedException:“Thread abort is not supported on this platform.” 。

后面关于异步的文章会讲解如何实现终止。

由于 .Net Core 不支持,就不理会这两个方法了。这里只列出 API,不做示例。

方法说明
Abort()在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。
Abort(Object)引发在其上调用的线程中的 ThreadAbortException以开始处理终止线程,同时提供有关线程终止的异常信息。 调用此方法通常会终止线程。

Abort() 方法给线程注入 ThreadAbortException 异常,导致程序被终止。但是不一定可以终止线程

2.5 线程的不确定性

线程的不确定性是指几个并行运行的线程,不确定在下一刻 CPU 时间片会分配给谁(当然,分配有优先级)。

对我们来说,多线程是同时运行的,但一般 CPU 没有那么多核,不可能在同一时刻执行所有的线程。CPU 会决定某个时刻将时间片分配给多个线程中的一个线程,这就出现了 CPU 的时间片分配调度。

执行下面的代码示例,你可以看到,两个线程打印的顺序是不确定的,而且每次运行结果都不同。

CPU 有一套公式确定下一次时间片分配给谁,但是比较复杂,需要学习计算机组成原理和操作系统

留着下次写文章再讲。

        static void Main(string[] args)        {            Thread thread1 = new Thread(Test1);            Thread thread2 = new Thread(Test2);            thread1.Start();            thread2.Start();            Console.ReadKey();        }        public static void Test1()        {            for (int i = 0; i < 10; i++)            {                Console.WriteLine("Test1:" + i);            }        }        public static void Test2()        {            for (int i = 0; i < 10; i++)            {                Console.WriteLine("Test2:" + i);            }        }

2.6 线程优先级、前台线程和后台线程

Thread.Priority 属性用于设置线程的优先级,Priority 是一个 ThreadPriority 枚举,其枚举类型如下

枚举说明
AboveNormal3可以将 安排在具有 Highest 优先级的线程之后,在具有 Normal 优先级的线程之前。
BelowNormal1可以将 Thread 安排在具有 Normal 优先级的线程之后,在具有 Lowest 优先级的线程之前。
Highest4可以将 Thread 安排在具有任何其他优先级的线程之前。
Lowest0可以将 Thread 安排在具有任何其他优先级的线程之后。
Normal2可以将 Thread 安排在具有 AboveNormal 优先级的线程之后,在具有 BelowNormal 优先级的线程之前。 默认情况下,线程具有 Normal 优先级。

优先级排序Highest > AboveNormal > Normal > BelowNormal > Lowest

Thread.IsBackgroundThread 可以设置线程是否为后台线程。

前台线程的优先级大于后台线程,并且程序需要等待所有前台线程执行完毕后才能关闭;而当程序关闭是,无论后台线程是否在执行,都会强制退出。

2.7 自旋和休眠

当线程处于进入休眠状态或解除休眠状态时,会发生上下文切换,这就带来了昂贵的消耗。

而线程不断运行,就会消耗 CPU 时间,占用 CPU 资源。

对于过短的等待,应该使用自旋(spin)方法,避免发生上下文切换;过长的等待应该使线程休眠,避免占用大量 CPU 时间。

我们可以使用最为熟知的 Sleep() 方法休眠线程。有很多同步线程的类型,也使用了休眠手段等待线程(已经写好草稿啦)。

自旋的意思是,没事找事做。

例如:

        public static void Test(int n)        {            int num = 0;            for (int i=0;i<n;i++)            {                num += 1;            }        }

通过做一些简单的运算,来消耗时间,从而达到等待的目的。

C# 中有关于自旋的自旋锁和 Thread.SpinWait(); 方法,在后面的线程同步分类中会说到自旋锁。

Thread.SpinWait() 在极少数情况下,避免线程使用上下文切换很有用。其定义如下

public static void SpinWait(int iterations);

SpinWait 实质上是(处理器)使用了非常紧密的循环,并使用 iterations 参数指定的循环计数。 SpinWait 等待时间取决于处理器的速度。

SpinWait 无法使你准确控制等待时间,主要是使用一些锁时用到,例如 Monitor.Enter。

“C#线程的创建和生命周期实例分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: C#线程的创建和生命周期实例分析

本文链接: https://lsjlt.com/news/322448.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C#线程的创建和生命周期实例分析
    本篇内容介绍了“C#线程的创建和生命周期实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1,获取当前线程信息Thread.Curren...
    99+
    2023-06-29
  • C#多线程系列之线程的创建和生命周期
    目录1,获取当前线程信息2,管理线程状态2.1启动与参数传递2.1.1ParameterizedThreadStart2.1.2使用静态变量或类成员变量2.1.3委托与Lambda2...
    99+
    2024-04-02
  • ES6中Promise生命周期和创建的示例分析
    这篇文章给大家分享的是有关ES6中Promise生命周期和创建的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一:Promise的概念Promise的中文意思是‘承诺&#...
    99+
    2024-04-02
  • Vue生命周期实例分析
    这篇文章主要介绍“Vue生命周期实例分析”,在日常操作中,相信很多人在Vue生命周期实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue生命周期实例分析”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-07-02
  • React的生命周期实例分析
    这篇文章主要讲解了“React的生命周期实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“React的生命周期实例分析”吧!一、React生命周期React 生命周期分为三种状态 初始化...
    99+
    2023-07-02
  • Laravel的生命周期实例分析
    本篇内容主要讲解“Laravel的生命周期实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Laravel的生命周期实例分析”吧!Laravel的生命周期 A世间万物皆有生命周期,当我们使用...
    99+
    2023-06-30
  • 小程序app.js生命周期实例分析
    这篇文章主要介绍了小程序app.js生命周期实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇小程序app.js生命周期实例分析文章都会有所收获,下面我们一起来看看吧。小程序的生命周期App.jsApp()...
    99+
    2023-06-26
  • Angular中的生命周期实例分析
    今天小编给大家分享一下Angular中的生命周期实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来...
    99+
    2024-04-02
  • Vue中的生命周期实例分析
    这篇文章主要介绍“Vue中的生命周期实例分析”,在日常操作中,相信很多人在Vue中的生命周期实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue中的生命周期实例分析”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-29
  • Spring创建Bean的生命周期详析
    目录1.Bean 的创建生命周期2.Spring AOP 大致流程3.Spring 事务4.Spring 源码阅读前戏BeanDefinitionBeanDefinitionRead...
    99+
    2024-04-02
  • Vue生命周期和MVVM框架实例分析
    这篇文章主要介绍“Vue生命周期和MVVM框架实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue生命周期和MVVM框架实例分析”文章能帮助大家解决问题。生命周期组件从开始到结束的全过程创建...
    99+
    2023-07-02
  • vue3生命周期原理与生命周期函数简单应用实例分析 原创
    原理概述 Vue 3的生命周期(Lifecycle)指的是组件从创建到销毁经历的一系列事件,在这些事件中可以执行一些操作,例如初始化数据、渲染视图、加载异步数据等。在Vue 3中,通...
    99+
    2023-05-17
    vue3 生命周期 生命周期函数 钩子函数
  • react生命周期的三个过程实例分析
    今天小编给大家分享一下react生命周期的三个过程实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起...
    99+
    2024-04-02
  • Vue组件生命周期实例分析
    本文小编为大家详细介绍“Vue组件生命周期实例分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“Vue组件生命周期实例分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1. 组件的生命周期的四个阶段组件的生命周...
    99+
    2023-06-27
  • Vue生命周期实例分析总结
    目录1. 概述2. 页面钩子函数3. 生命周期函数1. 概述 每个 Vue 实例在被创建之前都要经过一系列的初始化过程。例如需要设置数据监听、编译模板、挂载实例到 DOM、在数据变化...
    99+
    2024-04-02
  • Java之Bean的生命周期实例分析
    本篇内容主要讲解“Java之Bean的生命周期实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java之Bean的生命周期实例分析”吧!一、什么是生命周期首先理解下什么是生命周期从创建到消...
    99+
    2023-07-02
  • Vue2.0生命周期的示例分析
    这篇文章主要为大家展示了“Vue2.0生命周期的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Vue2.0生命周期的示例分析”这篇文章吧。网上已经有很多...
    99+
    2024-04-02
  • vue生命周期的示例分析
    这篇文章主要介绍了vue生命周期的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。vue生命周期图解感谢你能够认真阅读完这篇文章,希望小编分享的“vue生命周期的示例分...
    99+
    2023-06-14
  • Flutter组件生命周期和App生命周期示例解析
    目录引言无状态组件(StatelessWidget)有状态组件(StatefulWidget)StatefulWidget生命周期详细分析1. createState2. initS...
    99+
    2022-12-08
    Flutter 组件APP生命周期 Flutter 生命周期
  • Golang协程的创建与生命周期
    协程是一种轻量级线程,通过显式切换在同一调用栈复用执行单元。其生命周期包括创建、执行、挂起、恢复和完成。创建协程使用 go 关键字,实战中可用于并行计算(如计算斐波那契数列)。 Gol...
    99+
    2024-04-15
    生命周期 协程 golang
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作