C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行。一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为“主线程”)自动创建的,并具有多线程创建额外的线程。
除非被指定,否则所有的例子都假定以下命名空间被引用了:
using System;
using System.Threading;
C#开启线程的方法有:
- 异步委托
- 通过Thread类
- 线程池
- 任务
总的来说其实线程的开启基本都涉及到委托的使用。
一、异步委托开启线程
首先来看一个比较简单的例子,采用第一种开启线程的方法——异步委托
using System;
using System.Threading;
namespace Study
{
class Program
{
static void test()
{
Console.WriteLine("TestThread");
}
static void Main(string[] args)
{
Action a = test;
a.BeginInvoke(null, null);
Console.WriteLine("MainThread");
Console.ReadLine();
}
}
}
编译运行,发现结果与预期有所不同。结果如下图
如果按着逐行运行代码的方式,那么应该是先输出TestThread,但是结果却是先输出MainThread。
将a.BeginInvoke(null,null);
和Console.WriteLine("MainThread");
对调位置之后,结果和之前的依然一致。这就说明,异步委托开启的线程是和主线程同时同步进行的。
Action委托是指向一个没有返回值的函数,那么假设一个线程,我们需要取得他的返回结果并输出,那么就要用到Func委托。
看下面的源码
using System;
using System.Threading;
namespace SummerStudy
{
class Program
{
static string test(int i, string str)
{
Console.WriteLine("TestThread" + " 参数i是:" + i);
return str;
}
static void Main(string[] args)
{
Func<int, string, string> a = test;
IAsyncResult res = a.BeginInvoke(1, "返回值", null, null);
string o = a.EndInvoke(res);
Console.WriteLine("MainThread " + "线程返回值是:" + o);
Console.ReadLine();
}
}
同时异步委托开启线程中,判断线程是否结束的方法也有两种,一种是利用IAsyncResult的IsCompleted方法,一种是使用方法进行线程结束判断。
具体使用方法如下。
- IsCompleted(bool)
IAsyncResult ia = a.BeginInvoke()
if(ia.IsCompleted == false)
{
//GoOn
}
- AsyncWaitHandle
IAsyncResult ia = a.BeginInvoke()
ia.AsyncWaitHandle.WaitOne(Time);//Time为等待时间,超时后才会运行下一行代码,未完成直接跳出返回false
或者通过自定义方法,BeginInvoke中倒数第二个参数是一个委托,传递一个函数,在线程结束之后会自动的调用。
static string Test(int a)
{
}
Func<int, string> a = Test;
IAsyncResult ia = a.BeginInvoke(100, CallBack, a);
static void CallBack(IAsyncResult ar)
{
Func<int, string> a = ia.AsyncState as Func<int, string>;
string res = a.EndInvoke(ar);
}
在使用Lambda表达式作为委托的时候,最后一个参数可以为空,因为Lambda表达式可以访问外部变量。
二、使用Thread类开启线程
使用Thread类创建一个实例,它的构造方法中需要传递一个委托。通过委托绑定线程。
直接上代码
using System;
using System.Threading;
namespace Study
{
class Program
{
static void test()
{
Console.WriteLine("Thread");
Thread.Sleep(2000);
Console.WriteLine("TimeOver");
}
static void Main(string[] args)
{
Thread t = new Thread(test);
t.Start();
Console.WriteLine("Main");
Console.Read();
}
}
}
对于需要传递参数的委托,则必须制定参数类型为object,在线程Start方法中传递参数
namespace SummerStudy
{
class Program
{
static void test(object c)
{
int id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Thread, 线程id为" + id + ", 参数是:" + c);
Thread.Sleep(2000);
Console.WriteLine("TimeOver");
}
static void Main(string[] args)
{
Thread t = new Thread(test);
t.Start("xxx.avi");
Console.WriteLine("Main");
Console.Read();
}
}
}
当然你也可以自定义一个类,在类中自定义数据传递。
三、线程池
这种方法有助于节省时间,具体使用方法如下
using System;
using System.Threading;
namespace SummerStudy
{
class Program
{
static void test(object c)
{
int id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Thread, 线程id为" + id + ", 参数是:" + c);
Thread.Sleep(2000);
Console.WriteLine("TimeOver");
}
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(test, "asfasf");
Console.Read();
}
}
}
其中委托必须要有一个参数,无论是否使用该参数。且只适用于使用时间短的线程,不能改变优先级
四、任务
使用Task类开启线程,还有TaskFactory创建
Task类实例
using System;
using System.Threading;
using System.Threading.Tasks;
namespace SummerStudy
{
class Program
{
static void test(object c)
{
int id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Thread, 线程id为" + id);
Thread.Sleep(2000);
Console.WriteLine("TimeOver");
}
static void Main(string[] args)
{
Task t = new Task(test, "Asfgasg");
t.Start();
//或者
TaskFactory tf = new TaskFactory();
Task t1 = tf.StartNew(test);
Console.Read();
}
}
}
我的掘金:WarrenRyan
我的简书:WarrenRyan
欢迎关注我的博客获得第一时间更新 https://blog.tity.xyz
我的Github:WarrenRyan
我的博客园:WarrenRyan