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

posted @ 2023-10-08 09:43  青蛙001  阅读(43)  评论(0)    收藏  举报