多线程学习系列二(使用System.Threading)

一、什么是System.Threading.Thread?如何使用System.Threading.Thread进行异步操作

System.Threading.Thread:操作系统实现线程并提供各种非托管API来创建和管理线程,CLR封装这些非托管线程,在托管代码中通过System.Threading.Thread类来公开它们。

简单说就是System.Threading.Thread是一个创建和管理线程的类。

如何使用它来进行异步操作

publicclass Test

    {

        publicstaticintIndex =1000;

        publicstaticvoid Main()

        {

            //将DoWork方法设定为在Thread上执行的方法            ThreadStart threadStart = DoWork;

            //初始化Thread实例            Thread thread =new Thread(threadStart);

            //开启任务            thread.Start();

            for(inti =0; i < Index; i++)

            {

                Console.Write("-");

            }

            thread.Join();

            Console.ReadLine();

        }

        publicstaticvoid DoWork ()

        {

            for(inti =0; i < Index; i++)

            {

                Console.Write("+");

            }

        }

    }


  最开始Thread创建的新线程与Main函数的主线程轮流执行,相互切换。而不是先执行DoWork的输出+再执行后面的输出-,两个线程相互独立的,不会等待对方的执行。直到thread.Join()方法阻塞调用线程,直到thread实例的线程终止才执行其他的线程,这样就是一直执行完+,最后执行-


二、线程的管理

线程包含了大量的方法和属性,用于它们的执行。我们就来看一些常用的基本的方法和属性吧:

Join()。阻塞调用线程,直至此实例表示的线程终止,Join()方法的重载运行获得一个int或者TimeSpan作为参数,意思是指定最多等待Thread执行的时间,过期不候

IsBackGround。新线程默认为“前台”线程,操作系统将在进程中所有前台线程完成后终止进程。可以将thread.IsBackGround设置为True,这样就标记此线程为后台线程,这样后台线程任在进行,前台进程也允许终止。不过最好不要半路中止任何线程,最好是在线程退出之前显示的退出每一个线程。

Prioriy每个线程关联优先级的,这个属性就是设置线程的优先级(thread.Priority = ThreadPriority.Highest;(Lowest、BelowNormal、Normal、AboveNormal、Highest)),注意使用,避免造成“饥饿”的情况,一个高优先级的线程运行,其他低优先级的线程眼睁睁的看着

ThreadState。如果只是想要知道一个线程是否在运行或者是否已经完成了所有的工作的话,可以使用IsAlive。当然更全面的获得线程的详细的信息还是需要通过使用ThreadState来获取。

 

三、在生产代码中不要要线程进入睡眠

静态方法Thread.Sleep(),可以使当前方法进入睡眠—也就是告诉操作系统在指定的时间内不要为该线程调度任何的时间片。正如书中所说,这个设计表面看着合理,但是好好想下会发现有点不妥:

1、 操作系统不保证计时器的精确性,设置休眠100毫秒,操作系统会保证最少休眠100毫秒,但不一定就精确到100毫秒,可能时间会更长

2、 Thread.Sleep()经常被称为“穷人的同步系统”,意味着先把这个线程休眠,等当前异步工作完成。指望当线程休眠结束后当前异步工作也会完成,这并不是一个好的想法,因为异步操作花费的时间可能超出你的想象

3、 线程休眠不是一个好的编程实践,花费了昂贵的资源开启线程,但是却要它休眠,就好比花了大价钱雇了工人,然后要他去睡觉一样的。

当然有它的存在肯定会有其意义,其中一点:就是将线程的休眠的时间设置0,相当于告诉操作系统:“当前线程的时间片就送给其他的线程了。”然后,该线程会被正常调度,不会发生更多的延迟。其次Thread.Sleep()也可模拟高延迟的操作进行测试。


四、在生产代码中不要中止线程

Tread对象中Abort()方法一旦执行就是尝试销毁线程,会造成“运行时”在线程中引发异常,最好不要中止线程:

1、 该方法只是尝试销毁线程,不保证一定是成功的。

2、 中止线程时可能正处在lock代码块中,lock阻止不了异常,会导致中断,从而lock锁会自动释放。执行到一半的关键代码从而中断。违背了lock的原意,lock原意就是确保关键代码块的安全并防止其他线程进入的。

3、 线程终止时CLR保证自己内部的数据结构不会被破坏,但是BCL没有保证,所以中止线程可能导致数据结构或者BCL中的数据结构被破坏

五、线程池的处理

BCL提供的线程池可以使开发人员不是直接分配线程了,而是告诉线程池想要完成什么样的工作,工作结束后线程不是被销毁而是会回到线程池中,这样就节省了创建线程以及销毁线程所需要的开销。

在线程池中我们需要注意到的是:

1、要使用线程池向处理器受限任务高效的分配处理器的时间

2、避免把池中的工作者线程分配给I/O受限或者长时间运行的任务,如果需要可以考虑使用TPL,因为长时间的任务会造成工作的排队,那些排队的工作必定会受到延迟的。

你可能感兴趣的:(多线程学习系列二(使用System.Threading))