文章框架
线程开启方式
--1通过异步委托实现线程
----1.1定义线程
----1.2检测委托线程结束,通过while循环,等待句柄,函数回调
--2通过thread类开启线程
----2.1定义线程
----2.2如何传递参数
----2.3线程优先级
----2.4线程控制
--3、通过线程池开启线程
--4、通过任务开启线程
----4.1通过任务或任务工厂
----4.2连续任务
----4.3任务的层次结构
----4.4任务的执行结果
线程开启方式
1、通过异步委托实现线程
1.1定义线程
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Text10
{
class Program
{
static int Test(int n, string s)
{
Console.WriteLine(s + n);
return 10;
}
static void Main(string[] args)
{
Func func= Test;
func.BeginInvoke(1,"bey",null,null);
Console.WriteLine("hello,world!!!");
Console.ReadLine();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text10
{
class Program
{
static int Test(int n, string s)
{
Console.WriteLine(s + n);
Thread.Sleep(100);//让当前线程休眠
return 10;
}
static void Main(string[] args)
{
Func func= Test;
IAsyncResult ar= func.BeginInvoke(1,"bey",null,null);
Console.WriteLine("hello,world!!!");
while (ar.IsCompleted == false)//判断当前线程是否完成
{
Console.Write("-");
}
int res=func.EndInvoke(ar);//取得异步进程的返回值
Console.ReadLine();
}
}
}
1.2检测委托线程结束,通过等待句柄,函数回调
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text10
{
class Program
{
static int Test(int n, string s)
{
Console.WriteLine(s + n);
Thread.Sleep(100);//让当前线程休眠
return 10;
}
static void Main(string[] args)
{
//Func func= Test;
//IAsyncResult ar= func.BeginInvoke(1,"bey",null,null);
//Console.WriteLine("hello,world!!!");
////方法一 while循环
//while (ar.IsCompleted == false)//判断当前线程是否完成
//{
// Console.Write("-");
//}
//int res=func.EndInvoke(ar);//取得异步进程的返回值
////方法二:等待句柄
//bool isEnd=ar.AsyncWaitHandle.WaitOne(1000);//1000毫秒代表超时时间
//if (isEnd)
//{
// int res = func.EndInvoke(ar);
// Console.WriteLine(res);
//}
////方法三:函数回调
//Func func = Test;
//IAsyncResult ar = func.BeginInvoke(1, "bey", CallBack, func);
//简便写法lambda表达式
Func func = Test;
func.BeginInvoke(1, "bey", (ar)=>
{
int res = func.EndInvoke(ar);
Console.WriteLine(res);
}, null);
Console.ReadLine();
}
static void CallBack(IAsyncResult ar)
{
Func f = ar.AsyncState as Func;
int res = f.EndInvoke(ar);
Console.WriteLine(res);
}
}
}
2、通过thread类开启线程
2.1定义线程
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text11
{
class Program
{
static void DownLoadFile()
{
Console.WriteLine("开始下载");
Thread.Sleep(1000);
Console.WriteLine("下载结束");
}
static void Main(string[] args)
{
Thread thread = new Thread(DownLoadFile);
thread.Start();
Console.WriteLine("Main");
Console.ReadLine();
}
}
}
2.2如何传递参数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text11
{
class Program
{
static void DownLoadFile(object name)
{
Console.WriteLine("开始下载"+Thread.CurrentThread.ManagedThreadId+name);
Thread.Sleep(1000);
Console.WriteLine("下载结束");
}
static void Main(string[] args)
{
Thread thread = new Thread(DownLoadFile);
thread.Start("***的种子");
Console.WriteLine("Main");
Console.ReadLine();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text11
{
class MyThread
{
public string FileName { get; set; }
private string FilePath { get; set; }
public MyThread(string Name, string Path)
{
this.FileName = Name;
this.FilePath = Path;
}
public void DownLoadFile()
{
Console.WriteLine("开始下载" + FileName+"\n" +"文件地址:" +FilePath);
Thread.Sleep(1000);
Console.WriteLine("下载结束");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text11
{
class Program
{
////方法一
//static void DownLoadFile(object name)
//{
// Console.WriteLine("开始下载"+Thread.CurrentThread.ManagedThreadId+name);
// Thread.Sleep(1000);
// Console.WriteLine("下载结束");
//}
//static void Main(string[] args)
//{
// Thread thread = new Thread(DownLoadFile);
// thread.Start("***的种子");
// Console.WriteLine("Main");
// Console.ReadLine();
//}
//方法二
static void Main(string[] args)
{
MyThread myThread = new MyThread("XXX.bt","http://www.XXX.dbs");
Thread thread = new Thread(myThread.DownLoadFile);
thread.Start();
Console.ReadLine();
}
}
}
2.3前台线程和后台线程
线程有两种:前台线程和后台线程。区别是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
.net环境使用Thread建立的线程默认情况下是前台线程,即线程属性IsBackground=false,在进程中,只要有一个前台线程未退出,进程就不会终止。主线程就是一个前台线程。而后台线程不管线程是否结束,只要所有的前台线程都退出(包括正常退出和异常退出)后,进程就会自动终止。
后台线程只需将sBackground = true即可
thread.IsBackground = true;
2.4线程优先级
2.5控制线程
调用线程控制方法.启动:Thread.Start();停止:Thread.Abort();暂停:Thread.Suspend();继续:Thread.Resume();
值得注意的是: 通过 Thread.Abort() 停下来的线程(或自行运行结束的线程),都无法直接通过 Thread.Start() 方法再次启动,必须重新创建一个线程启动。
3、线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的[堆栈]大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在[托管代码]中空闲(如正在等待某个事件),则线程池将插入另一个[辅助线程]来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text11
{
class Program
{
static void DownLoadFile(object name)
{
Console.WriteLine("开始下载" + Thread.CurrentThread.ManagedThreadId + name);
Thread.Sleep(1000);
Console.WriteLine("下载结束");
}
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(DownLoadFile);
ThreadPool.QueueUserWorkItem(DownLoadFile);
ThreadPool.QueueUserWorkItem(DownLoadFile);
ThreadPool.QueueUserWorkItem(DownLoadFile);
ThreadPool.QueueUserWorkItem(DownLoadFile);
ThreadPool.QueueUserWorkItem(DownLoadFile);
ThreadPool.QueueUserWorkItem(DownLoadFile);
Console.ReadLine();
}
}
}
注意:线程池中的线程都是后台线程,不能修改为前台线程,不能设置优先级
4、通过任务开启线程
4.1通过任务或任务工厂
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text11
{
class Program
{
static void DownLoadFile()
{
Console.WriteLine("开始下载" );
Thread.Sleep(1000);
Console.WriteLine("下载结束");
}
static void DownLoadFile(object name)
{
Console.WriteLine("开始下载"+name );
Thread.Sleep(1000);
Console.WriteLine("下载结束");
}
static void Main(string[] args)
{
////方法一:任务
//Task task = new Task(DownLoadFile,"xxx");
//task.Start();
//方法二:任务工厂
TaskFactory taskFactory = new TaskFactory();
Task task = taskFactory.StartNew(DownLoadFile,"xxx");
Console.WriteLine("Main");
Console.ReadLine();
}
}
}
4.2连续任务
如果一个任务的执行依赖于另一个任务,即任务的执行有先后顺序。此时,我们可以使用连续任务。
task.ContinueWith(ReadNews)表示一个任务task结束后,才开始执行另一个任务。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text11
{
class Program
{
static void DownLoadFile(object name)
{
Console.WriteLine("开始下载" + name);
Thread.Sleep(1000);
Console.WriteLine("下载结束");
}
static void ReadNews(Task obj)
{
Thread.Sleep(1000);
Console.WriteLine("ReadNews");
}
static void Main(string[] args)
{
Task task = new Task(DownLoadFile, "xxx");
Task task2 = task.ContinueWith(ReadNews);
task.Start();
Console.WriteLine("Main");
Console.ReadLine();
}
}
}
4.3任务的层次结构
在一个任务中可以启动子任务,两个任务异步执行。默认情况下,子任务(即由外部任务创建的内部任务)将独立于其父任务执行。使用TaskCreationOptions.AttachedToParent显式指定将任务附加到任务层次结构中的某个父级。
如果父任务执行完了但是子任务没有执行完,则父任务的状态会被设置为WaitingForChildrenToComplete,只有子任务也执行完了,父任务的状态才会变成RunToCompletion。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text11
{
class Program
{
//任务的层次结构
static void DownLoad(object str)
{
Console.WriteLine("Parent Begin ID = " + Thread.CurrentThread.ManagedThreadId + " " + str);
Task child = new Task(ChildWork,TaskCreationOptions.AttachedToParent);
child.Start();
Thread.Sleep(1000);
Console.WriteLine("Parent 结束");
}
static void ChildWork()
{
Console.WriteLine("Child 开始");
Thread.Sleep(5000);
Console.WriteLine("Child 结束");
}
static void Main(string[] args)
{
Task task = new Task(DownLoad, "人民日报");
task.Start();
Thread.Sleep(2000);
Console.WriteLine(task.Status);
Thread.Sleep(4000);
Console.WriteLine(task.Status);
Console.WriteLine("Main");
Console.ReadLine();
}
}
}
4.4任务的执行结果
使用Task的泛型版本,可以返回任务的执行结果。
下面例子中的TaskWithResult的输入为object类型,返回一个元组Tuple
定义调用TaskWithResult的任务时,使用泛型类Task
任务完成后,通过Result属性获取任务的结果。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Text11
{
class Program
{
static void DownLoad(object str)
{
static Tuple TaskWithResult(object obj)
{
Tuple div = (Tuple)obj;
Thread.Sleep(1000);
return Tuple.Create(div.Item1 + div.Item2, div.Item1 - div.Item2);
}
static void Main(string[] args)
{
var task = new Task>(TaskWithResult, Tuple.Create(8, 3));
task.Start();
Console.WriteLine(task.Result);
task.Wait();
Console.WriteLine("Result: {0} {1}", task.Result.Item1, task.Result.Item2);
Console.ReadLine();
}
}
}
}