c# 线程使用总结
C# 里有好几种线程,每种有不同的实现方式,对应实现不同的功能,做个总结方便以后使用。
1. 委托
(1) 同步委托开启线程
不需要传参:
Action action1 = new Action(Count);// count 是一个计数函数 action1.Invoke();
需要传参:
Action<string> action2 = new Action<string>(Count);// Count是一个带有object参数的计数函数 action2.Invoke("线程开启");
总结:同步委托可以实现传参与不传参两种情况,但使用以后,界面卡顿,大多数情况下不宜使用
(2)异步委托开启线程
传递参数:
Action<string> action3 = new Action<string>(Count);// Count是一个带有object参数的计数函数 action3.BeginInvoke("线程开启", null, null);
传递参数并等待线程结束,传回线程运行之后的返回值:
private delegate int CallBack(string value);//带有返回值 int count = 0; private int Back(string str) { Stopwatch sp = new Stopwatch(); sp.Start(); for (int i = 10; i > 0; i--) { System.TimeSpan startTime = sp.Elapsed; while ((sp.Elapsed - startTime).TotalMilliseconds <= 1000) { System.Threading.Thread.Sleep(1); } TextChange(textBox1, str); TextChange(textBox2, i.ToString()); count++; } return count; } CallBack action = new CallBack(Back); IAsyncResult cookie = action.BeginInvoke("线程开启", null, null); int return= action.EndInvoke(cookie);
总结:如果只传递参数,异步线程不会卡顿,但如果需要等待线程结束 ,用到 action.EndInvoke,界面会卡顿,
这时外加上一个new Thread或者其他线程,可以解决卡顿问题,这个后面会说到。
(3) 通过thread开启线程
传递参数:
Thread thread = new Thread(new ParameterizedThreadStart(Count));// Count是一个带有object参数的计数函数 thread.Start("线程开启"); //Thread.Sleep(1000); //thread.Abort();//线程终止,立马停下,方法停止 //Console.WriteLine(thread.ThreadState);
或者用一个更简单的方式:
new Thread((value)=> { //这里直接写Count函数的内容 }).Start("线程开启");
不传递参数:
Thread thread = new Thread(new ThreadStart(Count));// Count是不带参数的计数函数 thread.Start(); //Thread.Sleep(1000); //thread.Abort();//线程终止,立马停下,方法停止 //Console.WriteLine(thread.ThreadState);
或者(这里演示用new thread解决action.EndInvoke卡顿问题):
new Thread(()=> { CallBack action = new CallBack(Back); IAsyncResult cookie = action.BeginInvoke("线程开启", null, null); int return= action.EndInvoke(cookie); int count = 0; private int Back(string str) { Stopwatch sp = new Stopwatch(); sp.Start(); for (int i = 10; i > 0; i--) { System.TimeSpan startTime = sp.Elapsed; while ((sp.Elapsed - startTime).TotalMilliseconds <= 1000) { System.Threading.Thread.Sleep(1); } TextChange(textBox1, str); TextChange(textBox2, i.ToString()); count++; } return count; } }).Start();
(4) timer开启线程
可以传递参数并循环执行:
System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(Count), "线程开启", Timeout.Infinite, Timeout.Infinite);// Count是一个带有object参数的计数函数 timer.Change(0, 0); //开启timer //Thread.Sleep(100); //timer.Change(-1, -1);//关闭timer,如果count函数没有执行完,不会停下,直到count函数执行完毕
总结:如果不需要传参,把“线程开启”换成null即可。
timer.Change(0,0) 中第一个0的位置表示开启时间(单位ms),0表示立马执行,-1表示永远不执行,第二个0的位置表示循环周期(单位ms),0或者-1表示不循环,其他正整数表示循环周期。
(5) Task开启线程
不传递参数(快速启动方式):
Task.Run(() => Count());//Count是一个计时函数
传递参数:
Task task = new Task(new Action<object>(Count), "线程开启", cts.Token);//无返回值的传参 task.Start(); //或者 Task.Factory.StartNew(new Action<object>(Count), "线程开启");
等待单个线程结束并返回结果:
int count = 0; private int Test2(object obj) { Stopwatch sp = new Stopwatch(); sp.Start(); for (int i = 5; i > 0; i--) { System.TimeSpan startTime = sp.Elapsed; while ((sp.Elapsed - startTime).TotalMilliseconds <= 1000) { System.Threading.Thread.Sleep(1); } TextChange(textBox2, i.ToString()); TextChange(textBox1, obj.ToString()); count++; } return count; } Func<object, int> func = new Func<object, int>(Test2); Task<int> task1 = new Task<int>(func, "线程开启"); task1.Start(); //if(task1.Result ==5) //直接写等待并判断会卡界面 //{ // TextChange(textBox6, task1.Result.ToString()); //} //开启另一个task2等待task1结束 Task task2 = task1.ContinueWith(reValue => { if (reValue.Result == 5) { TextChange(textBox6, reValue.Result.ToString()); } else { return; } });
等待多个线程全部运行结束,并返回结果 :
int count = 0; private int Test2(object obj) { Stopwatch sp = new Stopwatch(); sp.Start(); for (int i = 5; i > 0; i--) { System.TimeSpan startTime = sp.Elapsed; while ((sp.Elapsed - startTime).TotalMilliseconds <= 1000) { System.Threading.Thread.Sleep(1); } TextChange(textBox2, i.ToString()); TextChange(textBox1, obj.ToString()); count++; } return count; } List<int> resulesList = new List<int>(); List<Task<int>> taskList = new List<Task<int>>(); for (int i = 0; i < 5; i++) { taskList.Add(Task<int>.Factory.StartNew(new Func<object, int>(test2), i)); } Task.Factory.ContinueWhenAll(taskList.ToArray(), t => //通过回调完成主线程任务,ContinueWhenAll创建一组任务,该任务在指定的一组任务完成后开始 { for (int i = 0; i < 5; i++) { resulesList.Add(taskList[i].Result); } });
等待多个线程任一运行结束,并返回结果 :
Task.Factory.ContinueWhenAny
总结:Task线程的建立在一定程度上依赖于委托,通常,不需要返回值用Action,需要返回值用Func,也可以自建委托,
Task可以等待单一线程结束/多个线程结束/任一线程结束,分别对应不同的方法
(6) async / await 异步等待
没有返回值的等待:
private async void Waiting() { var t = Task.Run(() => { Thread.Sleep(5000); }); await t;
Console.WriteLine("等待结束"); }
等待返回值:
private async void Waiting() { var t = Task.Run(() => { Thread.Sleep(5000); return "线程结束"; }); textBox2.Text = await t; }
总结:这种方式可以等待结果,界面不卡顿,且跨线程修改控件属性问题也可以避免

浙公网安备 33010602011771号