一. Task的创建和运行,Task有如下三种方法创建
//Task的创建与运行
static void Main(string[] args)
{
//1.new 方式实例化一个Task,需要通过Start方法启动
Task task=new Task(()=>
{
Thread.Sleep(1000);
Console.WriteLine($"hello,task1的线程ID为:{0}",Thread.CurrentThread.ManagedThreadId);
});
task.Start();
//2.Task.Factory.StartNew(Action)创建和启动一个Task
Task task2=Task.Factory.StartNew(()=>
{
Thread.Sleep(1000);
Console.WriteLine($"hello,task2的线程ID为:{0}",Thread.CurrentThread.ManagedThreadId);
});
//3.Task.Run(Action action)将任务放到线程池队列中,返回并启动一个Task
Task task3=Task.Run(()=>
{
Thread.Sleep(1000);
Console.WriteLine($"hello,task3的线程ID为:{0}",Thread.CurrentThread.ManagedThreadId);
});
Console.WriteLine("执行主线程");
Console.ReadKey();
}
运行结果:
二.创建具有返回值的Task
如果使用Task.Result获取结果时会阻塞线程,即如果task没有完成,会等到task执行完成之后再执行后面的代码
static void Main(string[] args)
{
//1.使用New方法实例化一个Task,需要通过Start方法启动
Task task1=new Task(()=>
{
return $"hello,task1的id为{Thread.CurrentThread.ManagedThreadId}";
});
task1.Start();
//2.使用Task.Factory.StartNew()创建和启动一个Task
Task task2=Task.Factory.StartNew(()=>
{
return $"Hello,task2的id为{Thread.CurrentThread.ManagedThreadId}";
});
//3.Task.Run(Func func)将任务放在线程池队列,返回并启动一个Task
Task task3=Task.Run(()=>
{
return $"hello,task3的id为{Thread.CurrentThread.ManagedThreadId}";
});
Console.WriteLine("执行主线程");
Console.WriteLine(task1.Result);
Console.WriteLine(task2.Result);
Console.ReadKey();
}
运行结果:
如果阻塞线程,则需要RunSynchronously()来阻塞线程
static void Main(string[] args)
{
Task task=>new Task(()=>
{
Thread.Sleep(1000);
Console.WriteLine("执行Task结束");
});
//同步执行,task会阻塞线程
task.RunSynchronously();
Console.WriteLine("执行主线程结束");
Console.ReadKey();
}
运行结果:
三.Task的阻塞的方法
Wait:表示等待task执行完成,类似于Join()
WaitAll:当存在多个Task,只有所有的Task执行完成之后再解除阻塞
WaitAny:当存在多个Task,只要完成一个Task就解除阻塞
static void Main(string[] args)
{
Task task1=new Task(()=>
{
Thread.Sleep(500);
Console.WriteLine("线程1执行完成");
});
task1.Start();
Task task2=new Task(()=>
{
Thread.Sleep(1000);
Console.WriteLine("线程2执行完成");
});
task2.Start();
//阻塞线程。task1,task2都执行完毕再执行主线程
Task.WaitAll(new Task[]{task1,task2});
Console.WriteLine("主线程执行完毕!");
Console.ReadKey();
}
运行结果:
四:Task的延时操作
Wait/WaitAny/WaitAll的返回值为void,实现单纯阻塞线程.如果需要在执行完成之后再执行一些特定的代码则需要使用WhenAll/WhenAny。
task.WhenAll(Task[] tasks).ContinueWith:表示所有的task都执行完成之后再执行后续操作
task.WhenAny(Task[] tasks).ContinueWith:表示任意一个task执行完毕之后再执行后续操作
static void Main(string[] args)
{
Task task1=new Task(()=>
{
Thread.Sleep(500);
Console.WriteLine("task1执行完毕!");
});
task1.Start();
Task task2=new Task(()=>
{
Thread.Sleep(1000);
Console.WriteLine("task2执行完毕!");
});
task2.Start();
//task1与task2执行完成之后执行ContinueWith的后续操作
Task.WhenAll(task1,task2).ContinueWith((t)=>
{
Thread.Sleep(1000);
Console.WriteLine("执行后续的操作");
});
Console.WriteLine("主程序执行完毕!");
Console.ReadKey();
}
//下面这段代码的执行和上面是一样的,使用Task.Factory.ContinueWhenAll/ContinueWhenAny实现
static void Main(string[] args)
{
Task task1=new Task(()=>
{
Thread.Sleep(500);
Console.WriteLine("线程1执行完毕!");
});
task1.Start();
Task task2=new Task(()=>
{
Thread.Sleep(1000);
Console.WriteLine("线程2执行完毕!");
});
task2.Start();
//通过Task.Factory实现
Task.Factory.ContinueWhenAll(new Task[]{task1,task2},(t)=>
{
Thread.Sleep(1000);
Console.WriteLine("执行后续操作");
});
Console.WriteLine("主线程执行完毕!");
Console.ReadKey();
}
五:Task取消执行:CancelTokenSource,
Task不能像Thread一样粗暴的终止掉线程,abort();然后线程置为null;但是在实际开发中是有可能粗暴的终止线程的这时候只能使用Thread替换
static void Main(string[] args)
{
CancellationTokenSource source=new CancellationTokenSource();
int idx=0;
//开启一个task执行任务
Task task1=new Task(()=>
{
while(!source.IsCancellationRequested)
{
Thread.Sleep(1000);
Console.WriteLine($"第{++idx}次执行,线程执行中");
}
});
task1.Start();
//5秒后取消任务执行
//Thread.Sleep(5000);
//source.Cancel();
//也可以通过source.Token.Register(Action action)注册去取消任务触发毁掉函数
source.CancelAfter(10000);
Console.ReadKey();
}
运行结果:
六:通过Action实现异步的编程
private void btn_Click(object sender,EventArgs e)
{
Task.Run(()=>
{
Action setValue=(i)=>{txt1.Text=i.ToString();};
for(int i=0;i<100000;i++)
{
txt1.Text.Invoke(setValue,i);
}
});
}