线程是通过扩展 Thread 类创建的。扩展的 Thread 类调用 Start() 方法来开始子线程的执行。
using System; using System.Threading; namespace MulityThreadNote { class Program { static void Main(string[] args) { Thread t1 = new Thread(new ThreadStart(PrintNumbers));//无参数的委托 t1.Start(); Thread t2 = new Thread(new ParameterizedThreadStart(PrintNumbers));//有参数的委托 t2.Start(10); Console.ReadLine(); } static void PrintNumbers() { Console.WriteLine("Starting..."); for (int i = 0; i < 10; i++) { Console.WriteLine(i); } } //注意:要使用ParameterizedThreadStart,定义的参数必须为object //如果使用的是不带参数的委托,不能使用带参数的Start方法运行线程,否则系统会抛出异常。但使用带参数的委托,可以使用thread.Start()来运行线程,这时所传递的参数值为null。 static void PrintNumbers(object count) { Console.WriteLine("Starting..."); for (int i = 0; i < Convert.ToInt32(count); i++) { Console.WriteLine(i); } } } }
注释:我们只需指定在不同线程运行的方法名,而C#编译器会在后台创建这些对象
如果为了简单,也可以通过匿名委托或Lambda表达式来为Thread的构造方法赋值
static void Main(string[] args) { //通过匿名委托创建 Thread thread1 = new Thread(delegate() { Console.WriteLine("我是通过匿名委托创建的线程"); }); thread1.Start(); //通过Lambda表达式创建 Thread thread2 = new Thread(() => Console.WriteLine("我是通过Lambda表达式创建的委托")); thread2.Start(); Console.ReadKey(); }
运行结果:
Thread 类提供了各种管理线程的方法。
下面的实例演示了 sleep() 方法的使用,用于在一个特定的时间暂停线程。
using System; using System.Threading; namespace MultithreadingApplication { class ThreadCreationProgram { public static void CallToChildThread() { Console.WriteLine("Child thread starts"); // 线程暂停 5000 毫秒 int sleepfor = 5000; Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor / 1000); Thread.Sleep(sleepfor); Console.WriteLine("Child thread resumes"); } static void Main(string[] args) { ThreadStart childref = new ThreadStart(CallToChildThread); Console.WriteLine("In Main: Creating the Child thread"); Thread childThread = new Thread(childref); childThread.Start(); Console.ReadKey(); } } }
注释:也可使用Thread.Sleep(TimeSpan.FromSeconds(5));暂停线程
Abort() 方法用于销毁线程。
通过抛出 threadabortexception 在运行时中止线程。这个异常不能被捕获,如果有 finally 块,控制会被送至 finally 块。
下面的程序说明了这点:
using System; using System.Threading; namespace MultithreadingApplication { class ThreadCreationProgram { public static void CallToChildThread() { try { Console.WriteLine("Child thread starts"); // 计数到 10 for (int counter = 0; counter <= 10; counter++) { Thread.Sleep(500); Console.WriteLine(counter); } Console.WriteLine("Child Thread Completed"); } catch (ThreadAbortException e) { Console.WriteLine("Thread Abort Exception"); } finally { Console.WriteLine("Couldn‘t catch the Thread Exception"); } } static void Main(string[] args) { ThreadStart childref = new ThreadStart(CallToChildThread); Console.WriteLine("In Main: Creating the Child thread"); Thread childThread = new Thread(childref); childThread.Start(); // 停止主线程一段时间 Thread.Sleep(2000); // 现在中止子线程 Console.WriteLine("In Main: Aborting the Child thread"); childThread.Abort(); Console.ReadKey(); } } }
当上面的代码被编译和执行时,它会产生下列结果:
1 In Main: Creating the Child thread
2 Child thread starts
3 0
4 1
5 2
6 In Main: Aborting the Child thread
7 Thread Abort Exception
8 Couldn‘t catch the Thread Exception
using System; using System.Threading; namespace MulityThreadNote { class Program { static void Main(string[] args) { Console.WriteLine("Starting..."); Thread t = new Thread(PrintNumbersWithDelay); t.Start(); t.Join(); //使用Join等待t完成 PrintNumbers(); Console.WriteLine("THread Complete"); Console.ReadLine(); } static void PrintNumbers() { Console.WriteLine("Starting..."); for (int i = 0; i < 10; i++) { Console.WriteLine(i); } } static void PrintNumbersWithDelay() { Console.WriteLine("Starting..."); for (int i = 0; i < 10; i++) { Thread.Sleep(TimeSpan.FromSeconds(2)); Console.WriteLine(i); } } } }
注释:使用t.Join(); 等待t完成
using System; using System.Threading; namespace MulityThreadNote { class Program { static void Main(string[] args) { Console.WriteLine("Start Program..."); Thread t1 = new Thread(PrintNumbersWithStatus); Thread t2 = new Thread(DoNothing); Console.WriteLine(t1.ThreadState.ToString());//获取实例线程状态 t2.Start(); t1.Start(); for (int i = 0; i < 30; i++) { Console.WriteLine(t1.ThreadState.ToString()); } Thread.Sleep(TimeSpan.FromSeconds(6)); t1.Abort(); Console.WriteLine("thread t1 has been aborted"); Console.WriteLine(t1.ThreadState.ToString()); Console.WriteLine(t2.ThreadState.ToString()); Console.ReadLine(); } private static void PrintNumbersWithStatus() { Console.WriteLine("Starting..."); Console.WriteLine(Thread.CurrentThread.ThreadState.ToString());//获取当前线程状态 for (int i = 0; i < 10; i++) { Thread.Sleep(TimeSpan.FromSeconds(2)); Console.WriteLine(i); } } private static void DoNothing() { Thread.Sleep(TimeSpan.FromSeconds(2)); } } }
注释:使用Thread.ThreadState获取线程的运行状态。ThreadState是一个C#枚举。谨记:不要在程序中使用线程终止,否则可能会出现意想不到的结果
前台线程:只有所有的前台线程都结束,应用程序才能结束。默认情况下创建的线程都是前台线程
后台线程:只要所有的前台线程结束,后台线程自动结束。通过Thread.IsBackground设置后台线程。必须在调用Start方法之前设置线程的类型,否则一旦线程运行,将无法改变其类型。
通过BeginXXX方法运行的线程都是后台线程。
using System; using System.Diagnostics; using System.Threading; namespace MulityThreadNote { class Program { static void Main(string[] args) { //演示前台、后台线程 BackGroundTest background = new BackGroundTest(10); //创建前台线程 Thread fThread = new Thread(new ThreadStart(background.RunLoop)); //给线程命名 fThread.Name = "前台线程"; BackGroundTest background1 = new BackGroundTest(20); //创建后台线程 Thread bThread = new Thread(new ThreadStart(background1.RunLoop)); bThread.Name = "后台线程"; //设置为后台线程 bThread.IsBackground = true; //启动线程 fThread.Start(); bThread.Start(); } } class BackGroundTest { private int Count; public BackGroundTest(int count) { this.Count = count; } public void RunLoop() { //获取当前线程的名称 string threadName = Thread.CurrentThread.Name; for (int i = 0; i < Count; i++) { Console.WriteLine("{0}计数:{1}",threadName,i.ToString()); //线程休眠500毫秒 Thread.Sleep(1000); } Console.WriteLine("{0}完成计数",threadName); } } }
运行结果:前台线程执行完,后台线程未执行完,程序自动结束。
把bThread.IsBackground = true注释掉,运行结果:主线程执行完毕后(Main函数),程序并未结束,而是要等所有的前台线程结束以后才会结束。
后台线程一般用于处理不重要的事情,应用程序结束时,后台线程是否执行完成对整个应用程序没有影响。如果要执行的事情很重要,需要将线程设置为前台线程。
using System; using System.Diagnostics; using System.Threading; namespace MulityThreadNote { class Program { static void Main(string[] args) { ThreadSample sample = new ThreadSample(5); Thread t1 = new Thread(sample.CountNumbers); t1.Name = "ThreadOne"; t1.Start(); t1.Join(); Console.WriteLine("--------------------------"); Thread t2 = new Thread(Count); t2.Name = "ThreadTwo"; t2.Start(3); t2.Join(); Console.WriteLine("--------------------------"); //使用lambda表达式引用另一个C#对方的方式被称为闭包。当在lambda表达式中使用任何局部变量时,C#会生成一个类,并将该变量作为该类的一个属性,但是我们无须定义该类,C#编译器会自动帮我们实现 Thread t3 = new Thread(()=> CountNumbers(5)); t3.Name = "ThreadThree"; t3.Start(); t3.Join(); Console.WriteLine("--------------------------"); int i = 10; Thread t4 = new Thread(() => PrintNumber(i)); i = 20; Thread t5 = new Thread(() => PrintNumber(i)); t4.Start(); t5.Start(); //t4, t5都会输出20, 因为t4,t5没有Start之前i已经变成20了 Console.ReadKey(); } 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($"{Thread.CurrentThread.Name} prints {i}"); } } static void PrintNumber(int number) { Console.WriteLine(number); } } class ThreadSample { private readonly int _iteration; public ThreadSample(int iteration) { _iteration = iteration; } public void CountNumbers() { for (int i = 1; i <= _iteration; i++) { Thread.Sleep(TimeSpan.FromSeconds(0.5)); Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}"); } } } }
注释:也可以使用ThreadStart传递参数
sing System; using System.Diagnostics; using System.Threading; namespace MulityThreadNote { class Program { static void Main(string[] args) { Console.WriteLine("Incorrect Counter"); Counter c1 = new Counter(); var t1 = new Thread(() => TestCounter(c1)); var t2 = new Thread(() => TestCounter(c1)); var t3 = new Thread(() => TestCounter(c1)); t1.Start(); t2.Start(); t3.Start(); t1.Join(); t2.Join(); t3.Join(); Console.WriteLine($"Total Count: {c1.Count}"); Console.WriteLine("------------------------"); Console.WriteLine("Correct counter"); CounterWithLock c2 = new CounterWithLock(); t1 = new Thread(() => TestCounter(c2)); t2 = new Thread(() => TestCounter(c2)); t3 = new Thread(() => TestCounter(c2)); t1.Start(); t2.Start(); t3.Start(); t1.Join(); t2.Join(); t3.Join(); Console.WriteLine($"Total count:{c2.Count}"); Console.ReadLine(); } static void TestCounter(CounterBase c) { for (int i = 0; i < 100000; i++) { c.Increment(); c.Decrement(); } } class Counter : CounterBase { public int Count { get; private set; } public override void Decrement() { Count--; } public override void Increment() { Count++; } } class CounterWithLock : CounterBase { private readonly object _asyncRoot = new object(); public int Count { get; private set; } public override void Decrement() { lock (_asyncRoot) { Count--; } } public override void Increment() { lock (_asyncRoot) { Count++; } } } abstract class CounterBase { public abstract void Increment(); public abstract void Decrement(); } } class ThreadSample { private readonly int _iteration; public ThreadSample(int iteration) { _iteration = iteration; } public void CountNumbers() { for (int i = 1; i <= _iteration; i++) { Thread.Sleep(TimeSpan.FromSeconds(0.5)); Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}"); } } } }
注释:不加锁,得出的结果不确定,竞争条件下很容易出错。加锁得出的结果是正确的,但是性能受到了影响
using System; using System.Diagnostics; using System.Threading; namespace MulityThreadNote { class Program { static void Main(string[] args) { object lock1 = new object(); object lock2 = new object(); new Thread(() => LockTooMuch(lock1, lock2)).Start(); lock (lock2) { Thread.Sleep(1000); Console.WriteLine("Monitor.TryEnter allows not to get stuck, returning false after a specified timeout is elapsed"); //直接使用Monitor.TryEnter, 如果在第二个参数之前还未获取到lock保护的资源会返回false if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5))) { Console.WriteLine("Acquired a protected resource successfully"); } else { Console.WriteLine("Timeout acquiring a resource"); } } new Thread(() => LockTooMuch(lock1, lock2)).Start(); Console.WriteLine("-----------------------------"); /* 下面代码会造成死锁, 所以注释掉 lock (lock2) { Console.WriteLine("This will be a deadlock!"); Thread.Sleep(1000); lock (lock1) { Console.WriteLine("Acquired a protected resource successfully"); } } */ } static void LockTooMuch(object lock1, object lock2) { lock (lock1) { Thread.Sleep(1000); lock (lock2); } } } }
注释:Monitor.TryEnter在指定的时间内尝试获取指定对象上的排他锁
using System; using System.Diagnostics; using System.Threading; namespace MulityThreadNote { class Program { static void Main(string[] args) { Thread 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 faulty thread....."); Thread.Sleep(TimeSpan.FromSeconds(2)); //这个异常主线程无法捕捉到,因为是在子线程抛出的异常。需要在子线程中加入try...catch捕获异常 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: {ex.Message}"); } } } }
原文:https://www.cnblogs.com/zhaoyl9/p/12191973.html