Thread线程学习
Thread 类
- 是
.NetFrameWork对线程对象的封装,通过 Thread 完成的操作最终是通过向操作系统请求得到的执行流。 - 创建和控制线程,设置其优先级并获取其状态。
- 所在命名空间:
System.Threading Thread类创建的线程都是前台线程,设置IsBackground属性为true,可以将该线程设置为后台线程。
Thread th = new Thread(Test);
th.IsBackground = true;
th.Start();
前台线程和后台线程的区别:
前台线程和后台线程的主要区别就是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
构造函数
| Thread(ParameterizedThreadStart start) | 初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托。 |
|---|---|
| Thread(ParameterizedThreadStart start, int maxStackSize) | 初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托,并指定线程的最大堆栈大小。 |
| Thread(ThreadStart start) | 初始化 Thread 类的新实例。 |
| Thread(ThreadStart start, int maxStackSize) | 初始化 Thread 类的新实例,指定线程的最大堆栈大小。 |
- 前两个构造函数里面的
ParameterizedThreadStart参数,传递的是一个,带有一个object类型参数的委托,而且只能是object类型,并且只能传递一个参数。 - 后两个构造函数,也是传递的一个委托,但是该委托没有参数
常用的属性
| 属性 | 作用 |
|---|---|
| CurrentThread | 获取当前正在运行的线程。 |
| IsAlive | 获取指示当前线程的执行状态的值。如果此线程已启动并且尚未正常终止或中止,则为 true;否则为 false。 |
| IsBackground | 获取或设置一个值,该值指示某个线程是否为后台线程。 |
| IsThreadPoolThread | 获取指示线程是否属于托管线程池的值。 |
| ManagedThreadId | 获取当前托管线程的唯一标识符。 |
| Name | 获取或设置线程的名称。 |
| Priority(枚举类型) | 获取或设置指示线程的调度优先级的值。 |
| ThreadState(枚举类型) | 获取一个值,该值包含当前线程的状态。 |
常用的方法
| 方法 | 作用 |
|---|---|
| Sleep(int millisecondsTimeout) | 将当前线程挂起指定的毫秒数。 |
| Start() | 操作系统更改当前线程为 Running 状态 |
| Start(object? parameter) | 操作系统更改当前线程为 Running 状态,传递要使用的数据对象 |
| Join() | 插入当前正在执行的线程,直到由该实例表示的线程终止。 |
| Join(int millisecondsTimeout) | 插入当前正在执行的线程,直到由该实例表示的线程终止或经过了指定时间为止 |
创建一个线程
static void Main(string[] args)
{
Thread th = new Thread(Test);//使用new 创建一个线程
th.Start();//线程开始
Console.WriteLine("我是主线程");
Console.ReadKey();
}
private static void Test(object obj)
{
}
暂停线程
private static void Test(object obj)
{
//使用Sleep()方法,该线程会暂停2秒
//Sleep()方法,有两个重载,一个参数是int类型的,一个参数是TimeSpan类型的,两个方法使用效果都一样。
Thread.Sleep(2000);
Thread.Sleep(TimeSpan.FromSeconds(2));
}
- 当线程处于休眠状态时,它会占用尽可能少的 CPU 时间。
- 创建线程的时候,它会执行
Test()方法,然后会立即执行下面的代码,输出我是主线程
线程等待
static void Main(string[] args)
{
Thread th = new Thread(Test);//使用new 创建一个线程
th.Start();//线程开始
//插入主线程,等待该线程执行完毕后,在执行下面的代码
//Join()方法有,三个重载,另外两个重载的参数都是时间,表示要插入的时间限制
th.Join();
Console.WriteLine("我是主线程");
Console.ReadKey();
}
调用
Join()方法,该方法允许我们等待直到线程th完成。当线程th完成 "时,主程序会继续运行。借助该技术可以实现在两个线程间同步执行步骤。第一个线程会等待另一个线程完成后再继续执行。第一个线程等待时是处于阻塞状态(正如暂停线程中调用 Thread.Sleep 方法一样)
终止线程
Abort方法已被弃用
协作式取消(Cooperative Cancellation)——正确停止线程
使用CancellationTokenSource类
private static CancellationTokenSource cts = new CancellationTokenSource();
static void Main(string[] args)
{
Thread th = new Thread(Test);
th.Start();
Console.ReadLine();
//直接传达取消请求
cts.Cancel();
//在指定的毫秒数对CancellationTokenSource进行传达取消请求
cts.CancelAfter(1000);
Console.WriteLine("线程已经取消");
Console.WriteLine(th.ThreadState.ToString());
//主线程暂停1秒,是为了观察th线程的状态
Thread.Sleep(1000);
Console.WriteLine(th.ThreadState.ToString());
Console.ReadKey();
}
private static void Test()
{
while (true)
{
//CancellationTokenSource类对象调用Token属性
//Token属性是CancellationToken类的对象
//该属性调用IsCancellationRequested属性判断是否请求取消此标记
if (cts.Token.IsCancellationRequested)
{
Console.WriteLine("Cancled信号触发!");
//显示当前正在运行的线程的状态
Console.WriteLine(Thread.CurrentThread.ThreadState.ToString());
break;
}
Console.WriteLine(DateTime.Now.ToString());
Thread.Sleep(1000);
}
Console.WriteLine("线程终止!");
}
监控线程的状态
通过使用ThreadState属性来获取当前线程的状态
请注意始终可以通过 Thread.CurrentThread 静态属性获得当前 Thread 对象。
static void Main(string[] args)
{
Thread tha = new Thread(() =>
{
for (int i = 0; i < 2; i++)
{
Console.WriteLine("我是线程A");
//线程休眠两秒,执行主线程
Thread.Sleep(2000);
}
});
tha.Name = "线程A";
//线程开始之前处于ThreadState.Unstarted,线程还未开始
Console.WriteLine(tha.ThreadState);
tha.Start();
//调用Start()方法后,处于ThreadState.Running,线程已启动且尚未停止。
Console.WriteLine(tha.ThreadState);
//主线程休眠1秒,执行其他线程
Thread.Sleep(1000);
//tha线程休眠2秒时的状态,处于ThreadState.WaitSleepJoin,线程已被阻止。
Console.WriteLine(tha.ThreadState);
//主线程休眠4秒,执行其他线程
Thread.Sleep(4000);
//6秒后tha线程执行完毕的状态变为ThreadState.Stopped,线程已停止。
Console.WriteLine(tha.ThreadState);
Console.ReadKey();
}
向线程传递参数
public class Program
{
static void Main(string[] args)
{
Student student = new Student();
Thread th = new Thread(Test);
//在Start()方法中转入参数
th.Start(student);
Console.ReadKey();
}
/// <summary>
/// 如果向线程传递参数
/// 传入的参数必须是object类型
/// 只能传入一个参数
/// </summary>
/// <param name="obj">传入的数据对象</param>
private static void Test(object obj)
{
//在把obj参数转换成传入的对象类型
Student student = obj as Student;
}
}
public class Student
{
}
或者直接传递
Thread th = new Thread(()=>Test(7));
private static void Test(int i)
{
}
线程优先级
当主程序启动时定义了两个不同的线程。第一个线程优先级为ThreadPriority.Highest,即具有最高优先级。第二个线程优先级为ThreadPriority.Lowest,即具有最低优先级。我们先, ,打印出主线程的优先级值,然后在所有可用的 CPU 核心上启动这两个线程。如果拥有一个 1 以上的计算核心,将在两秒钟内得到初步结果。最高优先级的线程通常会计算更多的迭代.但是两个值应该很接近。然而,如果有其他程序占用了所有的 CPU 核心运行负载,结果则会截然不同。
异常处理
class Program
{
//如果直接使用线程,一般来说不要用try/catch包裹线程,而是在线程代码中使用try/catch代码块。
static void Main(string[] args)
{
var t = new Thread(FaultyThread);
t.Start();
t.Join();
//包裹线程的try-catch块,并没有捕获到执行方法内部的异常
try
{
t = new Thread(BadFaultyThread);
t.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static void BadFaultyThread()
{
Console.WriteLine("Starting a faulty thread...");
Thread.Sleep(TimeSpan.FromSeconds(2));
throw new Exception("Boom!");
}
//在线程执行方法内使用try-catch块,可以捕获异常
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);
}
}
}
参考https://www.cnblogs.com/wyt007/p/9486752.html

浙公网安备 33010602011771号