Thread类(线程)
操作系统通过线程对程序的执行进行管理,当操作系统运行一个程序的时候,首先,操作系统将为这个准备运行的程序分配一个进程,以管理这个程序所需要的各种资源。在这些资源之中,会包含一个称为主线程的线程数据结构,用来管理这个程序的执行状态。
在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创建的线程是前台线程,线程池中的是后台线程。
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类(线程)相关推荐
- java语言高级-Thread类线程安全问题
hui一.线程的安全问题: 这里使用窗口售票的例子,每个窗口相当于不同的线程,当不考虑线程安全问题时,此时会出现下面的情况 窗口2 当前剩余票:3 窗口3 当前剩余票:1 窗口2 当前剩余票:0 窗口 ...
- Java多线程-线程的创建(Thread类的基本使用)
文章目录 一. 线程和Thread类 1. 线程和Thread类 1.1 Thread类的构造方法 1.2 启用线程的相关方法 2. 创建第一个Java多线程程序 3. 使用Runnable对象创建线 ...
- 为什么wait、notify、notifyAll方法定义在Object中而不是Thread类中
多线程概述 Java是一个支持多线程的开发语言,多线程并发执行任务可以充分利用CPU资源,提高多任务并发执行效率(注意区分:多线程并不会加快任务的执行速度,而是可以充分利用多核CPU让线程轮流进行工作 ...
- C++多线程:thread类创建线程的多种方式
文章目录 描述 函数成员简介 总结 描述 头文件 <thread> 声明方式:std::thread <obj> 简介 线程在构造关联的线程对象时立即开始执行,从提供给作为构造 ...
- java 继承thread_java线程-创建线程(继承 Thread 类)
1.创建线程的方式 线程创建方式是:继承 Thread 类,重写 run 方法.如下:public class Task extends Thread{ @Override public void r ...
- java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...
学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...
- 05用线程类Thread开启线程
1.,密封类不能被继承 (thread) l类的内部的开启了,没有参数 2.要有参数 一定是object类型,(记住了) 3.自己创造线程 没有参数的时候 4.自己创造线程 有参数 用Thread开启 ...
- 在不是Thread类的子类中,如何获取线程对象的名称呢?
我想要获取main方法所在的线程对象的名称,该怎么办呢? 遇到这种情况,Thread类就提供了一个很好玩的方法: public static Thread currentThread() 返回当前正在 ...
- 线程的创建与启动——Thread 类有两个常用的构造方法:Thread()与 Thread(Runnable)||多线程运行结果是随机的
线程的创建与启动 在 Java 中,创建一个线程就是创建一个 Thread 类(子类)的对象(实例). Thread 类有两个常用的构造方法:Thread()与 Thread(Runnable).对应 ...
最新文章
- Microsoft Office Access ActiveX 部件不能创建对象
- sql2012简体中文版安装
- 更强的压缩比!PostgreSQL开始支持Zstd
- PHP做二次开发:ThinkCMF门户应用安装
- Spring框架–应用程序上下文–到达应用程序上下文的三种方法
- 多个python脚本同时执行_Python实现脚本锁功能(同时只能执行一个脚本)
- B+Tree及其创建过程
- 嵌入式Linux系统编程学习之十七计时器与信号
- OpenShift 4 - Knative教程 (6) Eventing之Channel和Subscription
- iphone开发工程师面试真题(又像c的)
- cassandra 避免 allow filter 提升性能的方法
- 重装正版Win10系统图文教程
- 自动合并两个.bib 去除.bib中的重复条目
- 符冉迪 计算机 培训,宁波大学考研研究生导师简介-符冉迪
- UNIX时间戳的UTC(协调世界时)
- css如何去掉图片里面存在的背景色
- 第二届长三角高校数学建模竞赛
- 华硕P10S-M主板组装服务器-raid配置方法
- 利用Python进行心脏病患者特征分析
- 10种常见的HTML标签错误写法