操作系统通过线程对程序的执行进行管理,当操作系统运行一个程序的时候,首先,操作系统将为这个准备运行的程序分配一个进程,以管理这个程序所需要的各种资源。在这些资源之中,会包含一个称为主线程的线程数据结构,用来管理这个程序的执行状态。

  在Windows操作系统下,线程的的数据结构包含以下内容:

  1、线程的核心对象:主要包含线程当前的寄存器状态,当操作系统调度这个线程开始运行的时候,寄存器的状态将被加载到CPU中,重新构建线程的执行环境,当线程被调度出来的时候,最后的寄存器状态被重新保存到这里,已备下一次执行的时候使用。
  2、线程环境块(Thread Environment Block,TED):是一块用户模式下的内存,包含线程的异常处理链的头部。另外,线程的局部存储数据(Thread Local Storage Data)也存在这里。
  3、用户模式的堆栈:用户程序的局部变量和参数传递所使用的堆栈,默认情况下,Windows将会被分配1M的空间用于用户模式堆栈。
  4、内核模式堆栈:用于访问操作系统时使用的堆栈。

在抢先式多任务的环境下,在一个特定的时间,CPU将一个线程调度进CPU中执行,这个线程最多将会运行一个时间片的时间长度,当时间片到期之后,操作系统将这个线程调度出CPU,将另外一个线程调度进CPU,我们通常称这种操作为上下文切换。

  在每一次的上下文切换时,Windows将执行下面的步骤:

  • 将当前的CPU寄存器的值保存到当前运行的线程数据结构中,即其中的线程核心对象中。
  • 选中下一个准备运行的线程,如果这个线程处于不同的进程中,那么,还必须首先切换虚拟地址空间。
  • 加载准备运行线程的CPU寄存器状态到CPU中。

  公共语言运行时CLR(Common Language Runtime)是.Net程序运行的环境,它负责资源管理,并保证应用和底层操作系统之间必要的分离。

  在.Net环境下,CLR中的线程需要通过操作系统的线程完成实际的工作,目前情况下,.Net直接将CLR中的线程映射到操作系统的线程进行处理和调度,所以,我们每创建一个线程将会消耗1M以上的内存空间。但未来CLR中的线程并不一定与操作系统中的线程完全对应。通过创建CLR环境下的逻辑线程,我们可能创建更加节省资源的线程,使得大量的CLR线程可以工作在少量的操作系统线程之上。

 

1. System.Threading.Thread类

System.Threading.Thread是用于控制线程的基础类,通过Thread可以控制当前应用程序域中线程的创建、挂起、停止、销毁。

它包括以下常用公共属性:

属性名称 说明
CurrentContext 获取线程正在其中执行的当前上下文。
CurrentThread 获取当前正在运行的线程。
ExecutionContext 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsAlive 获取一个值,该值指示当前线程的执行状态。
IsBackground 获取或设置一个值,该值指示某个线程是否为后台线程。
IsThreadPoolThread 获取一个值,该值指示线程是否属于托管线程池。
ManagedThreadId 获取当前托管线程的唯一标识符。
Name 获取或设置线程的名称。
Priority 获取或设置一个值,该值指示线程的调度优先级。
ThreadState 获取一个值,该值包含当前线程的状态。

 常用属性示例:

using System;
using System.Threading;namespace ConsoleApp
{class Program{static void Main(string[] args){//新建3个线程并设定各自的优先级Thread t1 = new Thread(Run);t1.Priority = ThreadPriority.Normal;t1.Start();Console.ReadKey();}public static void Run(){Thread t1 = Thread.CurrentThread;   //静态属性,获取当前执行这行代码的线程Console.WriteLine("我的优先级是:" + t1.Priority);Console.WriteLine("我是否还在执行:" + t1.IsAlive);Console.WriteLine("是否是后台线程:" + t1.IsBackground);Console.WriteLine("是否是线程池线程:" + t1.IsThreadPoolThread);Console.WriteLine("线程唯一标识符:" + t1.ManagedThreadId);Console.WriteLine("我的名称是:" + t1.Name);Console.WriteLine("我的状态是:" + t1.ThreadState);}}
}

View Code

2. 线程的标识符

ManagedThreadId是确认线程的唯一标识符,程序在大部分情况下都是通过Thread.ManagedThreadId来辨别线程的。而Name是一个可变值,在默认时候,Name为一个空值 Null,开发人员可以通过程序设置线程的名称,但这只是一个辅助功能。

 

3. 线程的优先级别

.NET为线程设置了Priority属性来定义线程执行的优先级别,里面包含5个选项,其中Normal是默认值。除非系统有特殊要求,否则不应该随便设置线程的优先级别。

成员名称 说明
Lowest 可以将 Thread 安排在具有任何其他优先级的线程之后。
BelowNormal 可以将 Thread 安排在具有 Normal 优先级的线程之后,在具有 Lowest 优先级的线程之前。
Normal 默认选择。可以将 Thread 安排在具有 AboveNormal 优先级的线程之后,在具有BelowNormal 优先级的线程之前。
AboveNormal 可以将 Thread 安排在具有 Highest 优先级的线程之后,在具有 Normal 优先级的线程之前。
Highest 可以将 Thread 安排在具有任何其他优先级的线程之前。

 优先级的示例:

using System;
using System.Threading;namespace ConsoleApp
{class Program{static void Main(string[] args){//新建3个线程并设定各自的优先级Thread t1 = new Thread(Run);t1.Priority = ThreadPriority.Lowest;Thread t2 = new Thread(Run);t2.Priority = ThreadPriority.Normal;Thread t3 = new Thread(Run);t3.Priority = ThreadPriority.Highest;//由低到高优先级的顺序依次调用
            t1.Start();t2.Start();t3.Start();Console.ReadKey();}public static void Run(){Console.WriteLine("我的优先级是:" + Thread.CurrentThread.Priority);}}
}

View Code

4. 线程的状态

通过ThreadState可以检测线程是处于Unstarted、Sleeping、Running 等等状态,它比 IsAlive 属性能提供更多的特定信息。

前面说过,一个应用程序域中可能包括多个上下文,而通过CurrentContext可以获取线程当前的上下文。

CurrentThread是最常用的一个属性,它是用于获取当前运行的线程。

 

5. System.Threading.Thread的方法

Thread 中包括了多个方法来控制线程的创建、挂起、停止、销毁,以后来的例子中会经常使用。

方法名称 说明
Abort()     终止本线程。
GetDomain() 返回当前线程正在其中运行的当前域。
GetDomainId() 返回当前线程正在其中运行的当前域Id。
Interrupt() 中断处于 WaitSleepJoin 线程状态的线程。
Join() 已重载。 阻塞调用线程,直到某个线程终止时为止。
Resume() 继续运行已挂起的线程。
Start()   执行本线程。
Suspend() 挂起当前线程,如果当前线程已属于挂起状态则此不起作用
Sleep()   把正在运行的线程挂起一段时间。

6. 开发实例

前台线程与后台线程的区别

  我们看到上面有个属性叫后台线程,非后台线程就叫前台线程吧,Thread.Start()启动的线程默认为前台线程,启动程序时创建的主线程一定是前台线程。应用程序与必须等到所有的前台线程执行完毕才会卸载。而当IsBackground设置为true时,就是后台线程了,当主线程执行完毕后就直接卸载,不再理会后台线程是否执行完毕。

  前台与后台线程的设置必须在线程启动之前进行设置,线程启动之后就不能设置了。

Thread创建的线程是前台线程,线程池中的是后台线程。

1、启动线程(.Start)
  1.1、无参数的调用
Thread t = new Thread(Action);
t.Start();
  1.2、带参数的调用方式一
Thread t = new Thread(Action<>);
t.Start(参数);
  1.3、带参数的调用方式二
Thread t = new Thread(() => Action<>(参数));
t.Start();
  1.4、如果遇到需要返回值,就可以考虑用异步;
public delegate string MethodCaller(string name);//定义个代理 
MethodCaller mc = new MethodCaller(GetName); 
string name = "my name";//输入参数 
IAsyncResult result = mc.BeginInvoke(name,null, null); 
string myname = mc.EndInvoke(result);//用于接收返回值 
public string GetName(string name)    // 函数
{
return name;
}

using System;
using System.Threading;namespace ConsoleApp1
{public delegate string MethodCaller(string name);//定义个代理 class Program{static void CountNumbers(){int _iterations = 3;for (int i = 1; i <= _iterations; i++){Thread.Sleep(TimeSpan.FromSeconds(0.5));Console.WriteLine("{0} prints {1}", Thread.CurrentThread.Name, i);}}static void Count(object iterations){CountNumbers((int)iterations);}static void CountNumbers(int iterations){for (int i = 1; i <= iterations; i++){Thread.Sleep(TimeSpan.FromSeconds(0.5));Console.WriteLine("{0} prints {1}", Thread.CurrentThread.Name, i);}}static void PrintNumber(int number){Console.WriteLine(number);}static string GetName(string name)    // 函数
        {int _iterations = 5;for (int i = 1; i <= _iterations; i++){Thread.Sleep(TimeSpan.FromSeconds(0.5));Console.WriteLine("{0} prints {1}", Thread.CurrentThread.Name, i);}return name;}static void Main(string[] args){//无参数的调用var threadOne = new Thread(CountNumbers);threadOne.Name = "ThreadOne";threadOne.Start();threadOne.Join();Console.WriteLine("--------------------------");//带参数的调用方式一var threadTwo = new Thread(Count);threadTwo.Name = "ThreadTwo";threadTwo.Start(3);threadTwo.Join();Console.WriteLine("--------------------------");//带参数的调用方式二var threadThree = new Thread(() => CountNumbers(4));threadThree.Name = "ThreadThree";threadThree.Start();threadThree.Join();Console.WriteLine("--------------------------");//注意在多个lambda表达式中使用香港的变量,它们会共享该变量 这里两个线程的参数都是20int i = 10;var threadFour = new Thread(() => PrintNumber(i));i = 20;var threadFive = new Thread(() => PrintNumber(i));threadFour.Start();threadFive.Start();Console.WriteLine("--------------------------");MethodCaller mc = new MethodCaller(GetName);string name = "my name";//输入参数 IAsyncResult result = mc.BeginInvoke(name, null, null);Console.WriteLine("继续主线程的业务");string myname = mc.EndInvoke(result);//用于接收返回值 Console.WriteLine(string.Format("result={0}", myname));}}
}

View Code

2、等待线程结束,会阻塞当前主线程(.Join)

using System;
using System.Threading;namespace ConsoleApp1
{class Program{static void Main(string[] args){Console.WriteLine("Starting program...");Thread t = new Thread(PrintNumbersWithDelay);t.Start();t.Join();Console.WriteLine("Thread completed");}static void PrintNumbersWithDelay(){Console.WriteLine("Starting...");for (int i = 1; i <= 5; i++){Thread.Sleep(TimeSpan.FromSeconds(1));Console.WriteLine(i);}}}
}

View Code

3、线程中异常的处理只能在线程调用中的函数里面去处理,在外面是接收不到线程中的报错的

using System;
using System.Threading;namespace ConsoleApp1
{class Program{static void Main(string[] args){var t = new Thread(FaultyThread);t.Start();t.Join();//try//{//    t = new Thread(BadFaultyThread);//    t.Start();//}//catch (Exception ex)//{//    //这里捕获不了线程中的异常//    Console.WriteLine("We won't get here!");//}
        }static void BadFaultyThread(){Console.WriteLine("Starting a Badfaulty thread...");Thread.Sleep(TimeSpan.FromSeconds(2));throw new Exception("Boom!");}static void FaultyThread(){try{Console.WriteLine("Starting a faulty thread...");Thread.Sleep(TimeSpan.FromSeconds(1));throw new Exception("Boom!");}catch (Exception ex){Console.WriteLine("Exception handled: {0}", ex.Message);}}}
}

View Code

4、设置线程优先级(.Priority)

using System;
using System.Diagnostics;
using System.Threading;namespace ConsoleApp1
{class Program{static void Main(string[] args){Console.WriteLine("Current thread priority: {0}", Thread.CurrentThread.Priority);Console.WriteLine("Running on all cores available");RunThreads();Thread.Sleep(TimeSpan.FromSeconds(2));Console.WriteLine("Running on a single core");Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);RunThreads();Console.ReadLine();}static void RunThreads(){var sample = new ThreadSample();var threadOne = new Thread(sample.CountNumbers);threadOne.Name = "ThreadOne";var threadTwo = new Thread(sample.CountNumbers);threadTwo.Name = "ThreadTwo";threadOne.Priority = ThreadPriority.Lowest;threadTwo.Priority = ThreadPriority.Highest;threadOne.Start();threadTwo.Start();Thread.Sleep(TimeSpan.FromSeconds(2));sample.Stop();}class ThreadSample{private bool _isStopped = false;public void Stop(){_isStopped = true;}public void CountNumbers(){long counter = 0;while (!_isStopped){counter++;}Console.WriteLine("{0} with {1,11} priority " +"has a count = {2,13}", Thread.CurrentThread.Name,Thread.CurrentThread.Priority,counter.ToString("N0"));}}}
}

View Code

转载于:https://www.cnblogs.com/scmail81/p/9297068.html

Thread类(线程)相关推荐

  1. java语言高级-Thread类线程安全问题

    hui一.线程的安全问题: 这里使用窗口售票的例子,每个窗口相当于不同的线程,当不考虑线程安全问题时,此时会出现下面的情况 窗口2 当前剩余票:3 窗口3 当前剩余票:1 窗口2 当前剩余票:0 窗口 ...

  2. Java多线程-线程的创建(Thread类的基本使用)

    文章目录 一. 线程和Thread类 1. 线程和Thread类 1.1 Thread类的构造方法 1.2 启用线程的相关方法 2. 创建第一个Java多线程程序 3. 使用Runnable对象创建线 ...

  3. 为什么wait、notify、notifyAll方法定义在Object中而不是Thread类中

    多线程概述 Java是一个支持多线程的开发语言,多线程并发执行任务可以充分利用CPU资源,提高多任务并发执行效率(注意区分:多线程并不会加快任务的执行速度,而是可以充分利用多核CPU让线程轮流进行工作 ...

  4. C++多线程:thread类创建线程的多种方式

    文章目录 描述 函数成员简介 总结 描述 头文件 <thread> 声明方式:std::thread <obj> 简介 线程在构造关联的线程对象时立即开始执行,从提供给作为构造 ...

  5. java 继承thread_java线程-创建线程(继承 Thread 类)

    1.创建线程的方式 线程创建方式是:继承 Thread 类,重写 run 方法.如下:public class Task extends Thread{ @Override public void r ...

  6. java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...

    学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...

  7. 05用线程类Thread开启线程

    1.,密封类不能被继承 (thread) l类的内部的开启了,没有参数 2.要有参数 一定是object类型,(记住了) 3.自己创造线程 没有参数的时候 4.自己创造线程 有参数 用Thread开启 ...

  8. 在不是Thread类的子类中,如何获取线程对象的名称呢?

    我想要获取main方法所在的线程对象的名称,该怎么办呢? 遇到这种情况,Thread类就提供了一个很好玩的方法: public static Thread currentThread() 返回当前正在 ...

  9. 线程的创建与启动——Thread 类有两个常用的构造方法:Thread()与 Thread(Runnable)||多线程运行结果是随机的

    线程的创建与启动 在 Java 中,创建一个线程就是创建一个 Thread 类(子类)的对象(实例). Thread 类有两个常用的构造方法:Thread()与 Thread(Runnable).对应 ...

最新文章

  1. Microsoft Office Access ActiveX 部件不能创建对象
  2. sql2012简体中文版安装
  3. 更强的压缩比!PostgreSQL开始支持Zstd
  4. PHP做二次开发:ThinkCMF门户应用安装
  5. Spring框架–应用程序上下文–到达应用程序上下文的三种方法
  6. 多个python脚本同时执行_Python实现脚本锁功能(同时只能执行一个脚本)
  7. B+Tree及其创建过程
  8. 嵌入式Linux系统编程学习之十七计时器与信号
  9. OpenShift 4 - Knative教程 (6) Eventing之Channel和Subscription
  10. iphone开发工程师面试真题(又像c的)
  11. cassandra 避免 allow filter 提升性能的方法
  12. 重装正版Win10系统图文教程
  13. 自动合并两个.bib 去除.bib中的重复条目
  14. 符冉迪 计算机 培训,宁波大学考研研究生导师简介-符冉迪
  15. UNIX时间戳的UTC(协调世界时)
  16. css如何去掉图片里面存在的背景色
  17. 第二届长三角高校数学建模竞赛
  18. 华硕P10S-M主板组装服务器-raid配置方法
  19. 利用Python进行心脏病患者特征分析
  20. 10种常见的HTML标签错误写法

热门文章

  1. 嵌入式Linux常用文件系统
  2. [K/3Cloud] KSQL 关联表更新字段Update语法
  3. ASP.NET 学习笔记_13 文章发布管理小系统
  4. 常用事件方法及技巧(二) -- MouseEvent(鼠标事件)
  5. U盘制做DOS启动盘
  6. mysql f参数_MySQL 数据类型
  7. Spring核心——Bean的依赖注入
  8. 团队作业第一次-团队团队展示
  9. JavaScript 的简单学习2
  10. 解决前端页面闪烁问题(转载)