线程
线程介绍
通过线程执行函数和直接在主函数中调用函数的区别是:通过直接调用函数时会按照语句顺序逐句执行,必定会完成上一句后再执行下一句,而通过线程执行的函数会从调用开始与主函数同步执行
调用线程的方式
调用无参数函数线程的方法:
void Start(){Thread thread = new Thread(SendThread);thread.Start();}void SendThread(){Debug.Log("调用线程");}
调用有参数函数线程时,使用lambda表达式在创建线程时传入函数的参数
void Start(){Thread t1 = new Thread(() => { SendThread("一", 100); });Thread t2 = new Thread(() => { SendThread("二", 50); });Thread t3 = new Thread(() => { SendThread("三", 25); });t1.Start();t2.Start();t3.Start();}void SendThread(string name,int i){while (i >= 0){Debug.Log(name + "执行剩余" + i--);}}
线程休眠
调用Thread.Sleep(int)方法
public static void Sleep(int millisecondsTimeout);
传入的参数为毫秒,1000毫秒等于一秒
//线程休眠一秒Thread.Sleep(1000);
线程池
线程池介绍
在调用线程的时候,会先创建线程,然后再线程结束后销毁线程,如果频繁对线程进行创建和销毁会极大的损耗计算机的性能,所以在频繁创建逻辑简短的线程的时候,最好使用线程池
调用线程池的方法
能够在线程池中调用的线程与直接创建线程不同的地方在于:线程池中调用的线程的参数必须限定格式,线程池能调用的线程必须只能拥有一个object类型的参数
通过ThreadPool.QueueUserWorkItem方法使用线程池调用线程
public static bool QueueUserWorkItem(WaitCallback callBack, object state);
第一个参数为想要执行线程的函数,函数必须只有一个object参数
第二个参数为传递给线程函数的参数
与直接创建线程不同的是,线程池中的线程不需要Start,添加线程时自动开始执行
示例代码:
void Start(){ThreadPool.QueueUserWorkItem(SendThreadPool,10);ThreadPool.QueueUserWorkItem(SendThreadPool,10.01);ThreadPool.QueueUserWorkItem(SendThreadPool,"十");}void SendThreadPool(object obj){for (int i = 0; i < 10; i++){Debug.Log(obj.ToString() + "剩余" + i);}}
设置线程池中最多同时运行线程数量
public static bool SetMaxThreads(int workerThreads, int completionPortThreads);
第一个参数为线程池中辅助线程的最大数目,与第二个参数相同即可
第二个参数为线程池中异步 I/O 线程的最大数目,与第一个参数相同即可
示例代码:
ThreadPool.SetMaxThreads(10,10);
线程同步
线程同步介绍
线程的运行是不规律的,结果不可控的,可能会涉及到一个线程中使用一个值之前这个值被另一个线程改变了,从而导致出现未知错误,这种情况下就需要控制线程执行的顺序,规避问题
Mutex 互斥锁
通过定义Mutex类型变量互斥锁,来达到同步效果,可以在执行重要逻辑前先对Mutex类型变量进行锁定,然后第二个线程尝试执行锁定Mutex变量时如果Mutex变量已被锁定,则第二个线程将会暂停运行,直到第一个锁定Mutex变量的线程将Mutex变量解锁,第二个线程才会继续锁定Mutex变量并开始工作,直到再次解锁Mutex变量为止
示例代码:
int number;Mutex mutex = new Mutex();void Start(){Thread t1 = new Thread(() => { SendThread("一",10); });Thread t2 = new Thread(() => { SendThread("二",8); });Thread t3 = new Thread(() => { SendThread("三",5); });t1.Start();t2.Start();t3.Start();}void SendThread(string name,int i){for (; i > 0; i--){mutex.WaitOne();for (int j = 0; j < i; j++){number += i;Debug.Log(name + "给数值增加了" + i + "现在的数值为" + number);}mutex.ReleaseMutex();}}
Lock 变量锁
通过Lock关键字来达到同步效果,和Mutex使用相似,执行重要逻辑前,锁住任意变量,将逻辑写入lock语句内,其余线程执行lock发现lock中的变量被锁住将会等待,等待前一线程的lock执行完毕释放lock关键字中的变量后再执行(lock锁住的变量可以和需要保护的变量毫无关系,可以锁住任意变量达到效果,但注意变量类型必须是引用类型,值类型变量无法使用lock关键字)
示例代码:
int number;object obj = new object();void Start(){Thread t1 = new Thread(() => { SendThread("一",10); });Thread t2 = new Thread(() => { SendThread("二",8); });Thread t3 = new Thread(() => { SendThread("三",5); });t1.Start();t2.Start();t3.Start();}void SendThread(string name,int i){for (; i > 0; i--){lock (obj) {for (int j = 0; j < i; j++){number += i;Debug.Log(name + "给数值增加了" + i + "现在的数值为" + number);}}Thread.Sleep(100);}}
Semaphore 多通道锁
Semaphore与Mutex不同的地方在于,Mutex一次只能固定允许一个线程访问,而Semaphore可以设置最多同时访问的最大数量,如果给Semaphore的最大访问值设置为2,同时有10个线程需要访问时,只有前2个线程能够成功访问,而剩余的8个线程则需要等待,等前两个线程执行完后,再同时让第3和第4个访问通道的线程执行,剩余的6个线程等待,直到执行完毕
示例代码:
int number;Semaphore semaphore = new Semaphore(2,2);void Start(){Thread t1 = new Thread(() => { SendThread("一", 10); });Thread t2 = new Thread(() => { SendThread("二", 8); });Thread t3 = new Thread(() => { SendThread("三", 5); });t1.Start();t2.Start();t3.Start();}void SendThread(string name, int i){for (; i > 0; i--){semaphore.WaitOne();for (int j = 0; j < i; j++){number += i;Debug.Log(name + "给数值增加了" + i + "现在的数值为" + number);}semaphore.Release();}}