我的编程空间,编程开发者的网络收藏夹
学习永远不晚

关于C#线程的全面解析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

关于C#线程的全面解析

线程的作用和意义

线程 被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程执行路径往往是有益的,每个线程执行特定的工作。

线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率。

到目前为止我们编写的程序是一个单线程作为应用程序的运行实例的单一的过程运行的。但是,这样子应用程序同时只能执行一个任务。为了同时执行多个任务,它可以被划分为更小的线程。

线程生命周期

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

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

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

C#创建线程

在C# 语言中使用线程时首先需要创建线程,在使用 Thread 类的构造方法创建其实例时,需要用到 ThreadStart 委托或者 ParameterizedThreadStart 委托创建 Thread 类的实例。ThreadStart 委托只能用于无返回值、无参数的方法,而ParameterizedThreadStart 委托则可以用于带参数的方法。

ThreadStar的方式创建

例子:

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        //线程函数
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
        }
        static void Main(string[] args)
        {
            //创建ThreadStart的委托实例
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            //创建Thread类的实例
            Thread childThread = new Thread(childref);
            childThread.Start(); //开始一个线程
            Console.ReadKey();
        }
    }
}

运行结果:

ParameterizedThreadStart

例子:

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建一个线程委托对象
            ParameterizedThreadStart pts = new ParameterizedThreadStart(PrintEven);
            Console.WriteLine("In Main: Creating the Child thread");
           // 创建一个线程对象
            Thread childThread = new Thread(pts);
            childThread.Start(10);
            Console.ReadKey();
        }
        //线程跑的函数
        //打印0~n中的偶数
        private static void PrintEven(Object n)
        {
            Console.WriteLine("Child thread started");
            for(int i=0; i<=(int)n; i+=2) //类型转换
            {
                Console.WriteLine(i);
            }
        }
    }
}

运行结果:

C#让线程休眠一会

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
            int sleepfor = 5000;
            Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor / 1000);
            Thread.Sleep(sleepfor);  //让线程暂停 单位毫秒
            Console.WriteLine("Child thread resumes");
        }
        static void Main(string[] args)
        {
            //创建一个线程的委托
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            //创建线程的实例
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
}

运行结果:最后一行是5s后才打印出来的

C#销毁线程


using System;
using System.Threading;
namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        //委托函数
        public static void CallToChildThread()
        {
            try//引起异常的语句
            {
                Console.WriteLine("Child thread starts");
                for(int counter = 0; counter <= 10; counter++)
                {
                    Thread.Sleep(500);
                    Console.WriteLine(counter);
                }
                Console.WriteLine("Child Thread Completed");
                   
            }
            catch(ThreadAbortException e)//错误处理代码
            {
                Console.WriteLine("Thread Abort Exception");
            }
            finally //执行的语句
            {
                Console.WriteLine("Could't catch the Thread Exception");
            }
        }
        static void Main(string[] args)
        {
            //创建一个线程的委托实例
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            //创建一个线程对象
            Thread childThread = new Thread(childref);
            childThread.Start();
            //主线程休眠
            Thread.Sleep(2000);
            Console.WriteLine("In Main:Aborting the Child thread");
            //在调用此方法的线程上引发ThreadAbortException,以开始终止此线程的过程。
            //调用此方法通常会终止线程
            childThread.Abort();
            Console.ReadKey();
        }
    }
}

运行结果:

C#线程优先级

在C#中线程的优先级使用线程的Priority属性设置即可,默认的优先级是Normal。在设置优先级后,优先级高的线程将优先执行。优先级的值通关ThreadPriority枚举类型来设置,从低到高分别为Lowest 、BelowNormal、Normal、 AboveNormal、 Highest。

例子:

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class Program
    {
        //奇数
        public static void PrintOdd()
        {
            Console.WriteLine("List of odd numbers:");
            for (int i = 1; i <= 100; i += 2)
            {
                Console.Write(i + " ");
            }
            Console.WriteLine();
        }
        //偶数
        public static void PrintEven()
        {
            Console.WriteLine("List of even numbers: ");
            for(int i = 0; i<=100; i+=2)
            {
                Console.Write(i + " ");
            }
            Console.WriteLine();
        }
        static void Main(string[] args)
        {
            //创建线程的委托1
            ThreadStart childref1 = new ThreadStart(PrintEven);
            Console.WriteLine("In Main: Creating the Child1 thread");
            //创建线程1的实例
            Thread childThread1 = new Thread(childref1);
            //设置打印偶数优先级为最低 
            childThread1.Priority = ThreadPriority.Lowest;
            //创建线程的委托2
            ThreadStart childref2 = new ThreadStart(PrintOdd);
            Console.WriteLine("In Main: Creating the Child2 thread");
            //创建线程2的实例
            Thread childThread2 = new Thread(childref2);
            //设置打印奇数优先级为最高 
            childThread2.Priority = ThreadPriority.Highest;
            childThread1.Start();//偶数  低
            childThread2.Start();//奇数  高
            Console.ReadKey();
        }
    }
}

运行的结果:

第一次运行:

第二次:

第三次:

第四次:

小结:

从上面的运行效果可以看出,由于输岀奇数的线程的优先级高于输出偶数的线程,所以在输出结果中优先输出奇数的次数会更多。

此外,每次输出的结果也不是固定的。通过优先级是不能控制线程中的先后执行顺序的,只能是优先级高的线程优先执行的次数多而已。

线程状态控制的方法包括暂停线程 (Sleep)、中断线程 (Interrupt)、挂起线程 (Suspend)、唤醒线程 (Resume)、终止线程 (Abort)。

lock:给线程加锁,保证线程同步

sleep 方法能控制线程的暂停时间,从而改变多个线程之间的先后顺序,但每次调用线程的结果是随机的。线程同步的方法是将线程资源共享,允许控制每次执行一个线程,并交替执行每个线程。在 C# 语言中实现线程同步可以使用 lock 关键字和 Monitor 类、Mutex 类来解决。对于线程同步操作最简单的一种方式就是使用 lock 关键字,通过 lock 关键字能保证加锁的线程只有在执行完成后才能执行其他线程。

lock的语法如下

lock(object)
 {
    //临界区代码
 }

这里 lock 后面通常是一个 Object 类型的值,也可以使用 this 关键字来表示。

最好是在 lock 中使用私有的非静态或负变量或私有的静态成员变量,即使用 Private 或 Private static 修饰的成员。

例如:

private Object obj = new Object();
lock (obj)
{
    //临界区代码
}

一个更具体的实例

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class Program
    {
        //打印偶数
        public void PrintEven()
        {
            //lock上锁保证执行完该线程才跑其他线程
           lock(this)
            {
                for(int i=0; i<=10; i+=2)
                {
                    //获取当前线程的名字
                    Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
                }
            }
        }
        //打印奇数
        public void PrintOdd()
        {
            lock (this)
            {
                for (int i = 1; i <= 10; i += 2)
                {
                    Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
                }
            }
        }
        static void Main(string[] args)
        {
            //因为下面要用到program类中的非静态函数,所以先创建该类对象
            Program program = new Program();
            //创建线程1的托管
            ThreadStart ts1 = new ThreadStart(program.PrintOdd);
            //创建线程1
            Thread t1 = new Thread(ts1);
            t1.Name = "打印奇数的线程";
            //跑线程1
            t1.Start();
            ThreadStart ts2 = new ThreadStart(program.PrintEven);
            Thread t2 = new Thread(ts2);
            t2.Name = "打印偶数的线程";
            t2.Start();
        }
    }
        
  
   
}

运行结果:

Monitor:锁定资源

和lock用法本质是一样的,使用Monitor类锁定资源的语法如下:

Monitor.Enter(object);
try
{
    //临界区代码
}
finally
{
    Monitor.Exit(object);
}

这里的object与lock中的object一样。

具体例子

sing System;
using System.Threading;
namespace MultithreadingApplication
{
    class Program
    {
        public void PrintEven()
        {
            //在指定对象上获取排它锁
            Monitor.Enter(this);
            try//临界区代码
            {
                for(int i=0; i<=10; i+=2)
                {
                    Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
                }
            }
            finally
            {
                //释放指定对象的排它锁
                Monitor.Exit(this);
            }
        }
        public void PrintOdd()
        {
            Monitor.Enter(this);
            try
            {
                for(int i=1; i<=10; i+=2)
                {
                    Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
                }
            }
            finally
            {
                Monitor.Exit(this);
            }
        }
        static void Main(string[] args)
        {
            //下面创建委托对象时调用的是Program类的非静态方法,
            //所先创建一个program对象
            Program program = new Program();
            //实例化一个委托
            ThreadStart ts1 = new ThreadStart(program.PrintOdd);
            //创建一个线程
            Thread t1 = new Thread(ts1);
            //给线程名字赋值
            t1.Name = "打印奇数的线程";
            //开跑线程
            t1.Start();
            ThreadStart ts2 = new ThreadStart(program.PrintEven);
            Thread t2 = new Thread(ts2);
            t2.Name = "打印偶数的线程";
            t2.Start();
        }
    }
}

运行结果:

Monitor 类的用法虽然比 lock 关键字复杂,但其能添加等待获得锁定的超时值,这样就不会无限期等待获得对象锁。使用 TryEnter() 方法可以给它传送一个超时值,决定等待获得对象锁的最长时间。

使用 TryEnter() 方法设置获得对象锁的时间的语法如下:

Monitor.TryEnter(object, 毫秒数 );

Mutex:互斥锁

Mutex类也是用于线程同步操作的类,当多个线程同时访问一个资源识保证只有一个线程访问资源。在Mutex类中,WaitOne()方法用于等待资源被释放,ReleaseMutex()方法用于释放资源。 WaitOne()方法在等待ReleMutex()方法执行后才会结束。

例子:

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class Program
    {
        //创建一个锁对象
        private static Mutex mutex = new Mutex();
        public static void PakingSpace(object num)
        {
            if(mutex.WaitOne())//等待释放资源,当前资源没调用时为true
            {
                try
                {
                    Console.WriteLine("车牌号{0}的车驶入!", num);
                    Thread.Sleep(1000);//线程休眠一秒
                }
                finally
                {
                    Console.WriteLine("车牌号{0}的车离开!", num);
                    mutex.ReleaseMutex(); //释放锁资源
                }
            }
        }
        static void Main(string[] args)
        {
            //创建一个委托带参数的
            ParameterizedThreadStart ts = new ParameterizedThreadStart(PakingSpace);
            //创建一个线程
            Thread t1 = new Thread(ts);
            t1.Start("A123456");
            Thread t2 = new Thread(ts);
            t2.Start("B00000");
            Console.ReadKey();
        }
    }
}

运行结果:

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

关于C#线程的全面解析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

关于Jar包部署命令全面解析

这篇文章主要介绍了Jar包部署命令全面解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2022-11-13

C/C++ extern关键字用法示例全面解析

这篇文章主要为大家介绍了C/C++ extern关键字用法示例全面解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-04

关于 Spring 中 GetBean 的全流程源码解析

最近有粉丝小伙伴反馈,与自己的上级沟通总是遇到障碍,感觉不被理解。大部分时候他提出来的事情都可能会被领导说:“我没get到你的点”、“你想做的这个项目没有业务价值”、“你提出问题,就要给出解决方案”,等等诸如此类的回答。

Android编程中关于单线程模型的理解与分析

本文讲述了Android编程中关于单线程模型的理解与分析。分享给大家供大家参考,具体如下: 当一个Android程序启动时,Android系统会同时启动一个对应的主线程(Main Thread)。 由于这个主线程(Main Thread)主
2022-06-06

如何进行关于线程池的分析

今天就跟大家聊聊有关如何进行关于线程池的分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。前言平时接触过多线程开发的童鞋应该都或多或少了解过线程池,之前发布的《阿里巴巴 Java 手
2023-06-16

java中关于线程同步的理解

首先了解什么是线程?我们可以在计算机上运行各种计算机软件程序。每一个运行的程序可能包括多个独立运行的线程(Thread)。 线程(Thread)是一份独立运行的程序,有自己专用的运行栈。线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等。 当多个线程
java中关于线程同步的理解
2021-11-21

关于C++的.cpp文件运行全过程

这篇文章主要介绍了C++的.cpp文件运行全过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-02-24

关于JAVA中多线程编程方法的详细解析(附实例)

一、程序、进程、线程程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码。它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文件。  从狭义来说,进程是正在运行的程序的实例;从广义上来说,进程
关于JAVA中多线程编程方法的详细解析(附实例)
2019-09-06

关于C语言多线程pthread库的相关函数说明

pthread库是C语言中用于多线程编程的一个标准库,包含了一系列的函数,用于创建、控制和管理线程。下面是一些常用的pthread库函数的简要说明:1. pthread_create:- 函数原型:int pthread_create(pt
2023-08-17

一篇文章带你全面解析不一样的线程

在将今天的知识点之前,大家是否了解线程,进程和协程了,那我们先来初步了解下吧。

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录