一、使用Thread类来实现
Thread类的实现方式,在C# .NetFramework刚出的时候就已经存在了,起初刚开始的程序员都使用这种方式,但经历后面几个.NetFramework的版本更新,实现方式变的更多了。
public static void TestThread() { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine("主线程id为:{0},总耗时为:{1}", Thread.CurrentThread.ManagedThreadId,watch.ElapsedMilliseconds); Thread thread = new Thread(TestAction); //设置线程相关属性 thread.IsBackground = true; thread.Name = "Test"; //启动线程 thread.Start(); watch.Stop(); Console.WriteLine("主线程id为:{0},总耗时为:{1}", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); } /// <summary> /// 线程执行的方法 /// </summary> private static void TestAction() { //这里实现线程处理的相关业务 Console.WriteLine($"子线程Thread({ Thread.CurrentThread.Name})的线程id为:{ Thread.CurrentThread.ManagedThreadId}"); }
运行结果:
一个任务(Task) 是可以设置多个延续任务的,这些任务是并行的,例如:
static void Main() { Task task = new Task(() => { Console.WriteLine(" 第一个任务"); Thread.Sleep(TimeSpan.FromSeconds(1)); }); // 任务① task.ContinueWith(t => { for (int i = 0; i < 5; i++) { Console.WriteLine($" 任务① "); Thread.Sleep(TimeSpan.FromSeconds(1)); } }); // 任务② task.ContinueWith(t => { for (int i = 0; i < 5; i++) { Console.WriteLine($" 任务②"); Thread.Sleep(TimeSpan.FromSeconds(1)); } }); // 任务① 和 任务② 属于同级并行任务 task.Start(); }
多个线程等待的情况
static void Main(string[] args) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine("主线程id为:{0},总耗时为:{1}", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); List<IAsyncResult> list = new List<IAsyncResult>(); for (int i = 0; i < 5; i++) { string name = string.Format("我是{0}", i); Action myFunc = () => { TestThread(name); }; var asyncResult = myFunc.BeginInvoke(null, null); list.Add(asyncResult); } //下面是线程等待 foreach (var item in list) { item.AsyncWaitHandle.WaitOne(-1); } watch.Stop(); Console.WriteLine("主线程id为:{0},总耗时为:{1}", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.ReadLine(); } static void TestThread(string name) { Thread.Sleep(1000); Console.WriteLine("子线程id为:{0},当前时间为:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now); }
结果:
List<ManualResetEvent> manualEvents = new List<ManualResetEvent>(); static void Main(string[] args) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine("-----------------Thread多线程 --------------------------"); Console.WriteLine("-----------------开始 主线程id为:{0} --------------------------", Thread.CurrentThread.ManagedThreadId); List<Thread> threadList = new List<Thread>(); Thread myThread = new Thread(() => { Console.WriteLine("我是子线程1"); Thread.Sleep(2000); }); //myThread.IsBackground = true; //设置为后台线程,主程序关闭所有线程均关闭 myThread.Start(); Thread myThread1 = new Thread(() => { Console.WriteLine("我是子线程2"); Thread.Sleep(2000); }); //myThread1.IsBackground = true; //设置为后台线程,主程序关闭所有线程均关闭 myThread1.Start(); threadList.Add(myThread); //利用join方法进行线程等待 foreach (Thread thread in threadList) { thread.Join(); } watch.Stop(); Console.WriteLine("----------------- 结束 主线程id为:{0} 总耗时:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.ReadKey(); } }
结果:
二、ThreadPool 线程池实现
public static void TestThreadPool() { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine("主线程id为:{0},总耗时为:{1}", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); //可以设置相关属性 ThreadPool.SetMinThreads(5, 10); ThreadPool.SetMaxThreads(6, 10); //通过线程池自动分配线程执行对应的业务功能 ThreadPool.QueueUserWorkItem(TestAction); Console.WriteLine("主线程id为:{0},总耗时为:{1}", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); } private static void TestAction(object state) { //这里实现线程处理的相关业务 Console.WriteLine($"子线程Thread({Thread.CurrentThread.Name})执行相关业务操作....{Thread.CurrentThread.ManagedThreadId}"); }
运行结果:
ThreadPool的使用是不是感觉比较简单,但是就是因为太简单了,在业务中有些需求得不到满足,比如试着控制线程顺序;
三、Delegate 实现的多线程
public static void TestDelegateThread() { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine("主线程id为:{0},总耗时为:{1}", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); //定义一个强类型委托, 可以自定义委托 Action action = TestAction; //开始异步操作,其实内部是开启了子线程,看线程id不一样就明白了 IAsyncResult asyncResult = action.BeginInvoke(CallBack, null); var aa=asyncResult.IsCompleted; //判读是否执行完成 //asyncResult.AsyncWaitHandle.WaitOne(); //阻塞当前线程,直到收到信号量 Console.WriteLine("主线程id为:{0},总耗时为:{1}", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); } //子线程执行完成时的回调 public static void CallBack(IAsyncResult ar) { Console.WriteLine($"子线程{ Thread.CurrentThread.ManagedThreadId}执行完毕"); } private static void TestAction() { Thread.Sleep(2000); //这里实现线程处理的相关业务 Console.WriteLine($"子线程Thread({Thread.CurrentThread.Name})执行相关业务操作....{Thread.CurrentThread.ManagedThreadId}"); }
运行结果:
注: 这种方式在.NetCore环境不支持,提示平台不支持。
线程内 给C# 窗体控件赋值
//1、声明委托类型,线程中设置Text public delegate void SetTextDelegate(string name, string text); //2、给控件赋值 public void SetText(string name, string text) { Control c = FindComponent(name);//查找name的控件 if (c != null) c.Text = text; //给text赋予值 } //3、可以线程内调用 Invoke(new SetTextDelegate(SetText), new object[] { "textBox1", "赋予控件文本的值!" });
Thread 单独传递参数
public void ExecSelf() { Thread t = new Thread(() => PubUploadMethod(docCode, sType)); t.Start(); } //上传数据组装 public JsonResult PubUploadMethod(string idStr,string sType) { }
使用InvokeDelegate方式
private delegate void InvokeDelegate();//上传后刷新数据的委托 public void SyncAllEmployee() { try { CommonHelper.SyncAllEmployee(); this.BeginInvoke(new InvokeDelegate(sx)); } catch (Exception ex) { Program.GetExceptionMsg(ex, null); } } public void sx() { //我是刷新的方法 }
窗体间
public const int CUSTOM_MESSAGE = 0X400 + 1001; [DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern IntPtr SendMessage(int hWnd, int msg, IntPtr wParam, IntPtr lParam); [DllImport("User32.dll", EntryPoint = "FindWindow")] private static extern int FindWindow(string lpClassName, string lpWindowName); public static void SendMsgToMainForm(int MSG, string windowName, int msgType) { int WINDOW_HANDLER = FindWindow(null, windowName); if (WINDOW_HANDLER == 0) { MessageBox.Show("未找到指定窗体"); } long result = SendMessage(WINDOW_HANDLER, CUSTOM_MESSAGE, new IntPtr(msgType), IntPtr.Zero).ToInt64(); } //调用 SendMsgToMainForm(CUSTOM_MESSAGE, main_window_name, 8000);
protected override void WndProc(ref System.Windows.Forms.Message msg) { switch (msg.Msg) { case Public_Class.CUSTOM_MESSAGE: switch (msg.WParam.ToString()) { case "8000": //可以调用窗体内控件 break; case "8001": break; default: break; } break; default: base.WndProc(ref msg); break; } }
其他