第14节:多线程 (前面讲了那么多c#知识,现在也终于该进入到最后一节了,本文来了解什么是多线程,下一节就要开启新篇章了,进入到Unity3d阶段,最近公司项目有点忙,所以可能会更新不及时,大家多多谅解啦!)
1.多线程
本文会通过代码加注释的形式来直接讲述多线程
线程中常用的方法:
1)线程对象.Start();开启线程
2)线程对象.AbOrton();终止线程
3)线程对象.Join();将当前线程睡眠,等待线程对象执行
完成后,将继续执行下面的代码
线程池:可以用来在后台执行多个任务的线程的集合。
可以协助主线程自由的异步执行其他任务。
线程池通常用于服务器应用程序(网络应用),每个传入的请求都将分配给线程池中的一个线程,进行异步的处理请求,而不用占用主线程,也不会延迟后续的请求的处理,一旦池中的某个线程完成后,它将返回到等待线程队列中,等待再次被使用。
这种线程对象的重用是的应用程序可以避免为每个任务建立新的线程开销,从而提高开发效率。
线程池通常具有做大线程数目的限制,如果所有的线程都很繁忙,则额外的任务将方法队列中,知道有线程可用时才能得到对应的处理。
可以自己通过线程类和集合类实现线程池,也可以使用系统提供的线程池类ThreadPool
注意:一般使用线程池来处理用的较短的任务,如果线程需要一直运行, 应该自己使用Thread开启线程。
例1:
using System;
using System.Threading;
namespace Duoxiancheng02
{
class MainClass
{
static void DownloadMovie()
{
Debug.Log ("下载视频"+Thread.CurrentThread.ManagedThreadId);
//休眠
Thread.Sleep(3000);
Debug.Log ("下载完成");
}
public static void DownloadMovie1(object fileName)
{
Debug.Log ("下载视频"+fileName.ToString());
Thread.Sleep(3000);
Debug.Log ("下载完成");
}
public static void MyThreadMethod(object state)
{
Debug.Log ("线程开始:"+Thread.CurrentThread.ManagedThreadId);
Thread.Sleep (2000);
Debug.Log ("线程结束");
}
public static void Main (string[] args)
{
//通过Thread类开启线程
//Thread.CurrentThread:获取当前线程
//Debug.Log (Thread.CurrentThread.ManagedThreadId);
//DownloadMovie ();
//1.创建Thread类对象,当前线程并没有开启
//Thread thread=new Thread(DownloadMovie1);
//开启执行线程
//thread.Start();
//线程开启带参数的方法
//thread.Start("xxxx.mp4");
//当前开启的线程thread对主线程中的语句没有影响
//Debug.Log ("当前是在主线程中....");
//2.使用Lambda表达式创建线程
// Thread thread1=new Thread(()=>{
// Debug.Log ("下载视频"+Thread.CurrentThread.ManagedThreadId);
// Thread.Sleep(2000);
// Debug.Log ("下载完成");
// });
// thread1.Start ();
// //3.将线程要传递的参数封装到类中
// MyThread my=new MyThread("http:hh.xxx.aaa","mmm.avi");
// //开启线程
// //这里可以传递静态方法和普通方法
// Thread thread2= new Thread (my.DownLoadFile);
// thread2.Start ();
// //当前线程(主线程)被休眠,需要等待thread2执行完成后继续执行下面的代码
// thread2.Join ();
// Debug.Log ("这是下面的代码");
ThreadPool.QueueUserWorkItem (MyThreadMethod);
ThreadPool.QueueUserWorkItem (MyThreadMethod);
ThreadPool.QueueUserWorkItem (MyThreadMethod);
ThreadPool.QueueUserWorkItem (MyThreadMethod);
ThreadPool.QueueUserWorkItem (MyThreadMethod);
ThreadPool.QueueUserWorkItem (MyThreadMethod);
ThreadPool.QueueUserWorkItem (MyThreadMethod);
ThreadPool.QueueUserWorkItem (MyThreadMethod);
}
}
}
例2:
using System;
using System.Threading ;
namespace Duoxiancheng02
{
public class MyThread
{
public MyThread ()
{
}
string fileName;
string filePath;
public MyThread(string fileName,string filePath)
{
this.fileName = fileName;
this.filePath = filePath;
}
public void DownLoadFile()
{
Debug.Log ("下载文件:"+filePath+fileName);
Thread.Sleep (2000);
Debug.Log ("下载文件完成");
}
}
}
例3:
using System;
using System.Threading;
namespace Duoxiancheng
{
class MainClass
{
//下载视频,一般我们会把比较耗时的操作放在单独开启的线程中去执行,比如:下载操作
public static int Test(int i)
{
Console.WriteLine ("下载视频"+i);
// //让当前线程休眠,单位是毫秒 1秒=1000毫秒
Thread.Sleep (1000);
// for (int a = 0; a < 10000; a++) {
// Console.Write (a);
// }
// Debug.Log ("下载完成!");
return 100;
}
//异步线程完成回调方法
public static void AsyncTreadFinishedCallback(IAsyncResult res)
{
//as 关键字:表示里氏转换(强制类型转换),可以将某个对象强制转换成某个类型,比如
//子类接收父类对象时,会报错,可以采用里氏转换来实现强制接收
Func<int,int> c= res.AsyncState as Func<int,int>;
int d = c.EndInvoke (res);
Debug.Log ("d="+d);
}
//计算1-10000之间的和
public static int Sum ()
{
int sum = 0;
for (int i = 1; i <= 10000; i++) {
sum += i;
}
return sum;
}
//异步求和结束时,系统自动回调的方法
public static void SumCallback (
IAsyncResult res)
{
Func<int> sumF = res.AsyncState as Func<int>;
int sum = sumF.EndInvoke (res);
Debug.Log ("1-10000之间的和为:" + sum);
}
public static void Main (string[] args)
{
//Test (2);
//Debug.Log ("Hello,world");
//通过委托来开启子线程
Func<int,int> a = Test;
//开启一个新的线程执行委托a所应用的耗时操作(下载方法)
//IAsyncResult res = a.BeginInvoke (100, null, null);
//Console.WriteLine ("res=" + res.IsCompleted);
Debug.Log ("这是一个主线程操作666");
//判断异步线程是否执行完成
//方法一:
// while (!res.IsCompleted) {
// Debug.Log ("正在下载视频中....");
// }
// Debug.Log ("下载完成!");
//方法二:通过等待句柄检测线程是否结束
//1000毫秒代表等待异步操作执行的超时时间
//表示如果等待了1000毫秒线程还没有结束,那么这个方法就会返回false,否则就返回true
// bool isEnd= res.AsyncWaitHandle.WaitOne(2000);
// if (isEnd) {
// int r= a.EndInvoke (res);
// Debug.Log ("r="+r);
// } else {
// Debug.Log ("异步操作结束");
// }
//方法三:通过检测回调方法来判断线程是否执行结束
// Func<int,int> b=Test ;
// b.BeginInvoke(100,AsyncTreadFinishedCallback,b);
//
// //练习:将上面的委托形式改成Lamda表达式形式
// b.BeginInvoke(100,(IAsyncResult res)=>{int d=b.EndInvoke(res);
// Debug.Log ("d="+d);},null);
//练习:在子线程中实现计算1-10000的和,在主线程中实现每隔100ms打印一次 Hello,world
//要求子线程中计算结果完成后,将结果打印出来,子线程执行结束,同时主线程打印也结束
// Func<int> sum=Sum;
// IAsyncResult result = sum.BeginInvoke (SumCallback, sum);
// int count = 0;
// while (!result.IsCompleted) {
// count++;
// Debug.Log ("Hello,world"+count);
// }
//保证应用程序不结束
}
}
}