【C#多线程】1.Thread类的使用及注意要点
Thread随便讲讲
因为在C#中,Thread类在我们的新业务上并不常用了(因为创建一个新线程要比直接从线程池拿线程更加耗费资源),并且在.NET4.0后新增了Task类即Async与await关键字,使得我们基本不再用Thread了,不过在学习多线程前,有必要先了解下Thread类,这里就先随便讲讲Thread。
1.使用多线程的几种方式
多线程Thread类只支持运行两种方法,一种是无参数并且无返回值的方法,第二种是有一个Object类型参数(有且只能有一个参数,并且必须是Object类型)且无返回值的方法。如果想让多线程方法携带多个参数,可以将多个参数放入一个集合或数组中传入方法。
下面例子使用了控制台来演示多线程的简单使用:
using System; using System.Threading; namespace ConsoleApplication1 { class Program { //无参数无返回值方法 public static void DoSomething() { for (int i = 0; i < 100; i++) { Thread.Sleep(500); } } //有参数无返回值方法 public static void DoSomethingWithParameter(object obj) { for (int i = 0; i < (int)obj; i++) { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); } } static void Main(string[] args) { //获取主线程ID int currentThreadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"---------主线程<{currentThreadId}>开始运行---------"); //多线程运行无参数方法方式1 ThreadStart ts = DoSomething;//ThreadStart是一个无参数,无返回值的委托 Thread thread1 = new Thread(ts); thread1.Start(); //多线程运行无参数方法方式2 Thread thread2 = new Thread(DoSomething);//可省略ThreadStart thread2.Start(); //多线程运行有参数方法方式1 //ParameterizedThreadStart是一个有一个Object类型参数,但是无返回值的委托。 ParameterizedThreadStart pts = DoSomethingWithParameter; Thread thread3 = new Thread(pts); thread3.Start(100); //多线程运行有参数方法方式2 //可以省略ParameterizedThreadStart Thread thread4 = new Thread(DoSomethingWithParameter); thread4.Start(100); //还可以使用lamda表达式简化多线程写法 new Thread(() => { for (int i = 0; i < 100; i++) { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); } }).Start(); Console.WriteLine($"---------主线程<{currentThreadId}>运行结束---------"); } } }
运行结果如下:
2.前台线程与后台线程
- 前台线程
如主线程(或称为UI线程)就是前台线程,默认Thread的实例均为前台线程,前台线程的特点是,如果当前应用的前台线程没有全部运行完毕,那么当前应用就无法退出。举个例子,我们知道正常情况下,控制台应用在Main方法结束后会自动结束当前进程,如果我们在Main方法中创建了一个新Thread线程,并使其保持运行,那么即使Main方法执行完毕,控制台进程也无法自动关闭(除非手动右上角点×)。就如下图情况,画红圈的地方表示Main方法执行完毕,可是程序依旧在运行,所以我们一般在用Thread的时候会将Thread设置为后台线程。
- 后台线程
后台线程与前台线程的唯一区别是,它不会去影响程序的生老病死,当程序的前台线程全部关闭(即程序退出),那么即使程序的后台线程依旧在执行任务,那么也会强制关闭。
设置Thread为后台线程的方式:
Thread tt = new Thread(DoSomething); tt.IsBackground = true;//设置tt为后台线程 tt.Start();
前台线程与后台线程对程序的影响效果看似好像不算大,但是如果我们在做Winform或者WPF项目时,若在某窗体内执行一个新线程任务(这个新线程是前台线程),如果在任务执行期间关闭程序,此时会发现,虽然界面都被关闭,但是计算机任务管理器中此程序依旧还在运行(并且如果在新线程中执行的任务异常导致线程无法关闭,那么这个程序就会一直在后台跑下去),再次开启程序可能会导致打不开等后果,这种行为是非常不好的。所以我们一般使用多线程Thread类时,最好顺手将它设置为后台线程。我们可以举个例子。
static void Main(string[] args) { //获取主线程ID int currentThreadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"---------主线程<{currentThreadId}>开始运行---------"); //执行一个大概可以运行50秒的新线程 Thread t = new Thread(() => { for (int i = 0; i < 100; i++) { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); } }); t.IsBackground = true;//设置t为后台线程 t.Start(); Console.WriteLine($"---------主线程<{currentThreadId}>运行结束---------" 288c ); }
这个例子的运行结果就不截图了,因为控制台会一闪而过(立即执行完Main方法便关闭),即使后台线程t还在执行任务,但是也会强制关闭。
3.让主线程等待新线程执行完成后再继续执行(使用Thread的Join方法)
直接上代码:
static void Main(string[] args) { //获取主线程ID int currentThreadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"---------主线程<{currentThreadId}>开始运行---------"); //执行一个大概可以运行50秒的新线程 Thread t = new Thread(() => { for (int i = 0; i < 20; i++) { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); } }); t.IsBackground = true;//设置t为后台线程 t.Start(); t.Join();//在t线程执行期间,如果主线程调用t线程的Join方法,主线程会卡在这个地方直到t线程执行完毕 Console.WriteLine($"---------主线程<{currentThreadId}>运行结束---------"); }
4.Thread实例的其他常用方法
直接看代码注释吧:
static void Main(string[] args) { //执行一个大概可以运行50秒的新线程 Thread t = new Thread(DoSth); t.IsBackground = true;//设置t为后台线程 t.Start(); t.Join();//在t线程执行期间,如果主线程调用t线程的Join方法,主线程会卡在这个地方知道t线程执行完毕 t.Priority = ThreadPriority.Normal;//设置线程调度的优先级 ThreadState rhreadState = t.ThreadState;//获取线程运行状态。 bool b = t.IsAlive;//获取线程当前是否存活 t.Interrupt();//中断当前线程 t.Abort();//终止线程 }
5.Thread类的常用方法
直接看代码注释吧:
static void Main(string[] args) { //使得当前线程暂停1秒再继续执行,此处会暂停主线程1秒钟 //如果写在其他线程执行的方法中,会让执行那个方法的线程暂停1秒再继续执行) Thread.Sleep(1000); //获取当前执行线程的线程实例 Thread t = Thread.CurrentThread; }
下节我们会简单讲讲线程池+同步回调+异步回调+跨线程访问UI。
- java多线程synchronized使用注意
- iPhone开发多线程使用与注意事项
- JAVA基础(多线程Thread和Runnable的使用区别(转载)
- Thread多线程学习(二),java多线程中synchronize锁的使用和学习
- iOS多线程编程之NSThread的使用
- std::string 内存管理特别,多线程使用时应注意
- SVN使用之注意要点
- 从头认识多线程-4.3 ThreadLocal使用时需要注意的地方
- [C++11 std::thread] 使用C++11 编写 Linux 多线程程序
- 达林顿驱动器ULN2003,ULN2803使用注意要点
- C#多线程编程之:lock使用注意事项
- C++使用thread类多线程编程
- 安装和使用Oracle VM VirtualBox中的要点,注意事项和遇到的问题
- 多线程(1) pthread(可无视) 2.NSThread(静态方法使用居多)
- iPhone开发进阶(11)--- 多线程的使用与注意事项
- 【知识点整理(java)】Java Thread简单使用注意点汇总(三)
- <Boost> boost::thread 多线程的使用
- libcurl 多线程使用注意事项(补充)——HTTPS,openssl多线程使用加锁
- Unity3D的Delegate和SendMessage的性能差测试,以及Delegate在多线程使用要注意的小问题
- STL list在多线程下使用需要注意的问题