Thread线程总结

一、使用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}");
}
View Code

运行结果:

一个任务(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();
            }
View Code

多个线程等待的情况

        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);
        }
View Code

 结果:

        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();
        }
    }
View Code

结果:

二、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}");
}
View Code

运行结果:

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}");
            
        }
View Code

运行结果:

注:  这种方式在.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;
    }
}

其他

  

作者:chenze
出处:https://www.cnblogs.com/chenze-Index/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果文中有什么错误,欢迎指出。以免更多的人被误导。
原文地址:https://www.cnblogs.com/chenze-Index/p/11593136.html