C# 多线程(Thread)、线程池(ThreadPool)、任务(Task)

线程和进程

进程:进程包含一个程序运行所需要的资源,进程即是一个程序,一个进程可以有多个线程。

线程:操作系统能够进行运算调度的最小单位。

Windows 任务管理器

进程可以有多个线程。

生命周期

UnStarted 处于创建但未启动状态

Runnable 调用了start,处于可运行或准备运行状态

Running 运行中状态

Not Runable 非运行状态,调用了sleep、wait或I/O被阻塞

Dead 任务完成后,处于死亡或终止状态

Thread

Thread 常用属性

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程:"+Thread.CurrentThread.ManagedThreadId);
            Thread t = new Thread(new ThreadStart(Thread_A));
            Console.WriteLine("创建线程 -- 线程状态:"+t.ThreadState);
            t.Start();
            Thread.Sleep(1000); //  睡眠1秒
            Console.ReadKey();
        }

        private static void Thread_A()
        {
            Console.WriteLine("常用属性值:");
            Console.WriteLine("当前运行线程实例:"+ Thread.CurrentThread);
            Console.WriteLine("当前线程唯一ID:"+Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("当前线程名称:"+Thread.CurrentThread.Name);
            Console.WriteLine("当前线程优先级:"+Thread.CurrentThread.Priority);
            Console.WriteLine("当前线程状态:"+Thread.CurrentThread.ThreadState);
            Console.WriteLine("当前线程是否处于活跃:"+Thread.CurrentThread.IsAlive);
            Console.WriteLine("当前线程是否为后台线程:"+Thread.CurrentThread.IsBackground);
           /*
           前台线程:主程序必须等待线程执行完毕后才能退出程序
					 后台线程:主程序执行完毕后就退出,不管线程是否完成
           */
        }
    }

输出

Thread 优先级

class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(A));
            t1.Start();
            Thread t2 = new Thread(new ThreadStart(B));
            t2.Start();
            Thread t3 = new Thread(new ThreadStart(C));
            t3.Start();
            Console.ReadKey();
        }

        private static void A()
        {
            Console.WriteLine("A");
        }
        private static void B()
        {
            Console.WriteLine("B");
        }
        private static void C()
        {
            Console.WriteLine("C");
        }
    }

第一次输出:ABC

第二次输出:BAC

第三次输出:ABC

第四次输出:ACB

第四次输出

Thread 优先级相同时没有先后顺序,设置优先级:

class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(A));
            t1.Start();
            t1.Priority = ThreadPriority.Highest;
            Thread t2 = new Thread(new ThreadStart(B));
            t2.Start();
            t2.Priority = ThreadPriority.Highest;
            Thread t3 = new Thread(new ThreadStart(C));
            t3.Start();
            t3.Priority = ThreadPriority.Highest;
            Thread t4 = new Thread(new ThreadStart(D));
            t4.Start();
            Console.ReadKey();
        }

        private static void A()
        {
            Console.WriteLine("A");
        }
        private static void B()
        {
            Console.WriteLine("B");
        }
        private static void C()
        {
            Console.WriteLine("C");
        }
        private static void D()
        {
            Console.WriteLine("D");
        }
    }

第一次输出:CABD

第二次输出:ABCD

第三次输出:ACBD

第四次输出:ACBD

D的优先级最低,ABC优先级都是 Highest,同优先级不分顺序

带参 Thread

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main,标识:"+Thread.CurrentThread.ManagedThreadId);
            Thread t1 = new Thread(new ParameterizedThreadStart(A)); // 带参数的方法
            t1.Start("ThreadTest"); // 传参
            Console.WriteLine("Main,标识:"+Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
        }

        private static void A(object data)
        {
            Console.WriteLine("Message: "+data+",标识:"+Thread.CurrentThread.ManagedThreadId);
        }
    }

输出

Thread 线程阻塞

Thread.Join() 可以阻塞主线程

class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() => { Console.WriteLine("A"); });
            t1.Start();
            t1.Join();
            Console.WriteLine("主线程");

            Console.Read();
        }
    }

输出

阻塞所有线程,t1 执行完成之后再执行其他线程

Thread.Sleep(); 阻塞当前线程

class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() =>
            {
                Console.WriteLine("A");
                Thread.Sleep(1000);
            });
            t1.Start();
            Console.WriteLine("主线程");

            Console.Read();
        }
    }

输出

当前线程阻塞1s,Thread.Sleep() 单位是ms

Thread 方法

来源:https://www.lidihuo.com/csharp/csharp-thread-class.html

Lock 线程锁

例:A、B同时在银行取钱,余额只有1000,两人都需要取1000,A取出来1000后,B取得时候提示余额不足

class Program
    {
        private static object obj = new object();
        private static int money = 1000;
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(Sum1);
            thread1.Start();
            Thread thread2 = new Thread(Sum1);
            thread2.Start();
            Console.ReadKey();
        }
        public static void Sum1()
        {
            lock (obj)
            {
                if(money >= 1000)
                {
                    money -= 1000;
                    Console.WriteLine("余额:{0}",money);
                }
                else
                {
                    Console.WriteLine("余额不足");
                }
            }
        }
    }

输出

ThreadPool

ThreadPool 线程池是为了方便对线程进行管理,线程池可以限制线程数量且可以重复使用

static void Main(string[] args)
        {
            Console.WriteLine("Main,标识:"+Thread.CurrentThread.ManagedThreadId);
            ThreadPool.QueueUserWorkItem(p => A("")); // A括号里面传参数
            ThreadPool.QueueUserWorkItem(new WaitCallback(A));
            Console.WriteLine("Main,标识:"+Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
        }

        private static void A(object data)
        {
            Console.WriteLine("Message: "+data+",标识:"+Thread.CurrentThread.ManagedThreadId);
        }

输出

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main,标识:"+Thread.CurrentThread.ManagedThreadId);
            Thread t1 = new Thread(new ThreadStart(A));
            Thread t2 = new Thread(new ThreadStart(B));
            t1.Start();
            t2.Start();
            Console.WriteLine("Main,标识:"+Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
        }
        private static void B()
        {
            Console.WriteLine("Thread B");
        }
        private static void A()
        {
            Console.WriteLine("Thread A");
        }
    }

输出

两端代码运行过多次,Thread 主线程会等待线程,ThreadPool 主线程不会等待线程

ThreadPool 线程重用、线程数量

线程数量

class Program
{
  static void Main(string[] args)
  {
  int workerThreads; // 工作线程
  int completionPortThreads; // I/O 线程
  ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
  Console.WriteLine(#34;最大线程数:{workerThreads},{completionPortThreads}");
  ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
  Console.WriteLine(#34;最小线程数:{workerThreads},{completionPortThreads}");
  Console.ReadLine();
  }
}

输出

设置数量

class Program
    {
        static void Main(string[] args)
        {
            int workerThreads; // 工作线程
            int completionPortThreads; // I/O 线程
            // 设置最大线程
            ThreadPool.SetMaxThreads(5, 5);
            // 设置最小线程
            ThreadPool.SetMinThreads(1, 1);
            ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
            Console.WriteLine(#34;最大线程数:{workerThreads},{completionPortThreads}");
            ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
            Console.WriteLine(#34;最小线程数:{workerThreads},{completionPortThreads}");
            Console.ReadLine();
        }
    }

输出

线程重用

class Program
    {
        static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney));
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney));
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney));
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney));
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney));
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney));
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney));
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetMoney));
            Console.ReadKey();
        }

        private static void GetMoney(object state)
        {
            Console.WriteLine("线程标识: "+Thread.CurrentThread.ManagedThreadId);
        }
    }

输出

从输出的线程标识中可以看出只用了三个线程,减少了线程的创建

带参 ThreadPool

class Program
    {
        static void Main(string[] args)
        {
            string msg = "The User Does't exit";
            object mg = "Hello Banananana";
            ThreadPool.QueueUserWorkItem((a) => Message(msg));
            ThreadPool.QueueUserWorkItem(new WaitCallback(Message), mg); // 传参类型需要 Object
            Console.Read();
        }

        private static void Message(string msg)
        {
            Console.WriteLine(msg);
        }
        private static void Message(object msg)
        {
            Console.WriteLine(msg+"");
        }
    }

输出

QueueUserWorkItem

回调方法

Task

ThreadPool 不能控制线程执行的顺序,也不能获取线程池内线程的取消、异常、完成的通知

Task 无返回值线程

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("开始执行");

            var factory = new TaskFactory();
            Task t1 = factory.StartNew(() => Console.WriteLine("A,标识: {0}",Thread.CurrentThread.ManagedThreadId));

            Task t2 = Task.Factory.StartNew(() => Console.WriteLine("B,标识: {0}",Thread.CurrentThread.ManagedThreadId));

            Task t3 = new Task(() => Console.WriteLine("C,标识: {0}",Thread.CurrentThread.ManagedThreadId));
            t3.Start();

            Task t4 = Task.Run(() => Console.WriteLine("D,标识: {0}",Thread.CurrentThread.ManagedThreadId));

            Console.Read();
        }
    }

输出

Task 有返回值线程

class Program
    {
        static void Main(string[] args)
        {
            Task t1 = new Task(() => { return #34;A, 标识:{Thread.CurrentThread.ManagedThreadId}"; });
            t1.Start();
            Task t2 = Task.Factory.StartNew(() => { return #34;B, 标识:{Thread.CurrentThread.ManagedThreadId}"; });
            Task t3 = Task.Run(() => { return #34;C, 标识:{Thread.CurrentThread.ManagedThreadId}"; });

            Console.WriteLine(t1.Result);
            Console.WriteLine(t2.Result);
            Console.WriteLine(t3.Result);

            Console.Read();
        }
    }

输出

注:Task.Result 返回结果时会阻塞线程

Task 同步执行

class Program
    {
        static void Main(string[] args)
        {
            Task t1 = new Task(() => Console.WriteLine("Task 线程"));

            t1.RunSynchronously(); // 同步方法
            Console.WriteLine("主线程");

            Console.Read();
        }
    }

输出

Task 线程阻塞

Thread 也有方法可以进行阻塞,但每次只能对一个线程进行阻塞,Task 可以有方法可以解决这个问题,task.Wait() 等待 task 执行完成,类似 Thread.Join(),Task.WaitAll() 执行完所有 task 再解除线程,Task.WaitAny() 只要有一个 task 执行完成就解除线程

Task.Wait

class Program
    {
        static void Main(string[] args)
        {
            Task t1 = new Task(() => { Console.WriteLine("A"); });
            t1.Start();
            t1.Wait();
            Console.WriteLine("主线程");

            Console.Read();
        }
    }

Task.Wait()

阻塞所有线程,等待当前执行完成


Task.WaitAll

class Program
    {
        static void Main(string[] args)
        {
            List list = new List();
            Task t1 = Task.Run(() => Console.WriteLine("A"));
            Task t2 = Task.Run(() => Console.WriteLine("B"));
            Task t3 = Task.Run(() => Console.WriteLine("C"));
            Task t4 = Task.Run(() => Console.WriteLine("D"));

            list.Add(t1);
            list.Add(t2);
            list.Add(t3);
            list.Add(t4);
            Task.WaitAll(list.ToArray());

            Console.WriteLine("主线程");

            Console.Read();
        }
    }

Task.WaitAll

等待 Task线程组 完成


Task.WaitAny

class Program
    {
        static void Main(string[] args)
        {
            List list = new List();
            Task t1 = Task.Run(() => Console.WriteLine("A"));
            Task t2 = Task.Run(() => Console.WriteLine("B"));
            Task t3 = Task.Run(() => Console.WriteLine("C"));
            Task t4 = Task.Run(() => Console.WriteLine("D"));

            list.Add(t1);
            list.Add(t2);
            list.Add(t3);
            list.Add(t4);
            Task.WaitAny(list.ToArray());

            Console.WriteLine("主线程");

            Console.Read();
        }
    }

Task.WaitAny

线程组任意线程完成就接触阻塞

Task 延续操作

有一个需求,需要在 task 线程组 执行完成之后执行

class Program
    {
        static void Main(string[] args)
        {
            List list = new List();
            Task t1 = Task.Run(() => Console.WriteLine("A"));
            Task t2 = Task.Run(() => Console.WriteLine("B"));
            Task t3 = Task.Run(() => Console.WriteLine("C"));
            Task t4 = Task.Run(() => Console.WriteLine("D"));

            list.Add(t1);
            list.Add(t2);
            list.Add(t3);
            list.Add(t4);

           // 二选一即可
            Task.WhenAll(list.ToArray()).ContinueWith(t => Console.WriteLine("执行完成"));
            // Task.Factory.ContinueWhenAll(list.ToArray(), t => Console.WriteLine("执行完成"));

            Console.WriteLine("主线程");

            Console.Read();
        }
    }

输出

从输出中可以看出,task 不会阻塞主线程

有一个需求,需要在 task 线程任意线程执行完成之后执行

class Program
    {
        static void Main(string[] args)
        {
            List list = new List();
            Task t1 = Task.Run(() => Console.WriteLine("A"));
            Task t2 = Task.Run(() => Console.WriteLine("B"));
            Task t3 = Task.Run(() => Console.WriteLine("C"));
            Task t4 = Task.Run(() => Console.WriteLine("D"));

            list.Add(t1);
            list.Add(t2);
            list.Add(t3);
            list.Add(t4);

           //  二选一即可
            Task.WhenAny(list.ToArray()).ContinueWith(t => Console.WriteLine("执行完成"));
            // Task.Factory.ContinueWhenAny(list.ToArray(), t => Console.WriteLine("执行完成"));

            Console.WriteLine("主线程");

            Console.Read();
        }
    }

输出

这个方法也不会阻塞主线程

Task 任务取消

有一个下载任务已运行,但这个文件已经不需要了,需要取消这个下载任务

class Program
    {
        static void Main(string[] args)
        {
            var cts = new CancellationTokenSource();
            int i;
            Task t1 = new Task(() =>
            {
                i = 0;
                while (!cts.IsCancellationRequested)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine(#34;下载中:{i++}%");
                    if(cts.IsCancellationRequested)
                        Console.WriteLine("下载已取消");
                }
            });
            t1.Start();
            // cts.Cancel();    //  立刻取消
            cts.CancelAfter(1000 * 10);  // 10秒后取消
            Console.Read();
        }
    }

输出

除了使用 if 语句输出 下载已取消,CancellationTokenSource 也有一个自带的注册任务取消事件

class Program
    {
        static void Main(string[] args)
        {
            var cts = new CancellationTokenSource();
            int i;
            Task t1 = new Task(() =>
            {
                i = 0;
                while (!cts.IsCancellationRequested)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine(#34;下载中:{i++}%");
                }
            });
            // 取消后执行
            cts.Token.Register(() =>
            {
                Console.WriteLine("下载已取消");
            });
            t1.Start();
            cts.CancelAfter(1000 * 10);
            Console.Read();
        }
    }

输出

异步方法(async/await)

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(GetContentAsync().Result);

            Console.Read();
        }

				// 不会阻塞线程
        async static Task GetContentAsync()
        {
            Encoding GB2312 = Encoding.GetEncoding("GB2312");
            Encoding GBK = Encoding.GetEncoding("GBK");
            FileStream fs = new FileStream(@"D:\1.txt", FileMode.Open);
            byte[] bytes = new byte[fs.Length];
            Console.WriteLine("开始读取文件");
            int len = await fs.ReadAsync(bytes,0,bytes.Length);
            string res = Encoding.UTF8.GetString(bytes);
            return res;
        }
    }

输出

Task 对ThreadPool做了封装,主要是为了更好地控制线程池中的线程


完!坚持and放弃,我选择坚持

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章