扎实基础_多线程

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static SemaphoreSlim semLim = new SemaphoreSlim(3); //3表示最多只能有三个线程同时访问
        static void Main(string[] args)
        {
            //线程的意义,一个应用程序,如果有多个可执行部分,可以同时执行 如同时开启 多个线程进行爬虫
            //对于比较耗时的IO,数据库,或者WCF通信,可以单独开启后台线程执行,这样主线程就不会阻塞了,等执行完了,再通知主线程

            //知识点:线程同步,异步线程,循环线程, 跨线程访问
            #region 信号量(Semaphore)
                for (int i = 0; i < 10; i++)
                {
                    new Thread(SemaphoreTest).Start();
                }
                Console.Read();
            #endregion

            #region Taks线程
                //1.new方式实例化一个Task任务,需要通过Start方式启动
                Task task = new Task(() =>
                {
                    Console.WriteLine($"hello");
                });
                task.Start();

                //task.Factory.StartNew(Action action) 创建和启动一个Task任务
                Task task1 = Task.Factory.StartNew(() =>
                {
                    Console.WriteLine($"hello");
                });

                //task.Run(action action)
                Task task2 = Task.Run(() =>
                {
                    Thread.Sleep(100);
                    Console.WriteLine($"hello");
                });
            #endregion

            #region Thread .net 4.0加入的
                //通俗讲解Thread 一个人走路回家,突然想起老婆交代没有买盐, 正常情况 要么买完盐回家,要么回家之后再去买盐
                //但是他学会一个Thread技能:于是Thread分身处一个自己去买盐 ,自己的主体边回家
                //但是自己主体如果回到家了,Thread还没买到盐,那么也就不需要Thread了

                Console.WriteLine("主线程开始");
                //IsBackground=true,将其设置为后台线程
                Thread t = new Thread(Run) { IsBackground = true };
                t.Start();
                Console.WriteLine("主线程在做其他的事!");
                //主线程结束,后台线程会自动结束,不管有没有执行完成
                //Thread.Sleep(300);
                Thread.Sleep(1500);
                Console.WriteLine("主线程结束");

            #endregion

            #region ThreadPoll
                //通俗讲解ThreadPoll   走路回家,突然想起老婆交代没买 柴米油盐,姜醋茶 如果还是用Thread分身那么 买柴创建一个分身
                //买米,买油,买盐,都需要创建 等创建好了,家也快到了,还是挨老婆打
                //THreadPoll线程池,相当于你已经创建好了分身,需要买什么就叫一个分身去买,但是ThreadPoll也是有最大限制 比如10个
                //如果超过了限制,那么就需要重新创建新的线程,如果10个 只需要7个去执行,其他就会被设置成空闲状态,7个执行完了也会被设置成空闲状态,而不会消失


                ThreadPool.QueueUserWorkItem(m =>
                    {
                        Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
                    });

            #endregion

            #region MyRegion async/await  .NET 4.5 ,C# 5.0

                //async用来修饰方法,表明这个方法是异步的,声明的方法的返回类型必须为:void,Task或Task < TResult >。

                //await必须用来修饰Task或Task < TResult >,而且只能出现在已经用async关键字修饰的异步方法中。通常情况下,async / await成对出现才有意义,
                Console.WriteLine("-------主线程启动-------");
                Task<int> taskAsync = GetStrLengthAsync();
                Console.WriteLine("主线程继续执行");
                Console.WriteLine("Task返回的值" + taskAsync.Result);
                Console.WriteLine("-------主线程结束-------");


            #endregion

            #region 线程同步 是指在某一时刻只有一个线程可以访问变量
                // c#为同步访问变量提供了一个非常简单的方式,即使用c#语言的关键字Lock,它可以把一段代码定义为互斥段,
                //互斥段在一个时刻内只允许一个线程进入执行,实际上是Monitor.Enter(obj),Monitor.Exit(obj)的语法糖。在c#中,lock的用法如下:
                //lock (obj) { 需要执行的代码 }

                BookShop book = new BookShop();
                //创建两个线程同时访问Sale方法
                Thread t1 = new Thread(book.Sale);
                Thread t2 = new Thread(book.Sale);
                //启动线程
                t1.Start();
                t2.Start();
                Console.ReadKey();
            #endregion

            #region  跨线程访问

            #endregion

            #region 知识点 
            //1.利用Thread新建线程和调用Task都是用非主线程异步执行工作,主线程不等待,
            //  不同点是Task使用线程池线程,任务结束后线程不会销毁,资源开销相对于Thread新建线程相对小一点。
            //2.Task和直接Task.Run没有区别。
            //3.利用await只能调用有async声名的方法主线程在await处等待异步执行结果,
            //但是此时主线程不会被阻塞掉。(如果此时主线程不去处理其他的事情,
            //那么和Thread调用线程,对于使用者来说是没有区别的)
            #endregion


            #region 属性名称    说明
            //CurrentThread         获取当前正在运行的线程。
            //ExecutionContext      获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
            //IsBackground          bool,指示某个线程是否为后台线程。
            //IsThreadPoolThread    bool,指示线程是否属于托管线程池。
            //ManagedThreadId       int, 获取当前托管线程的唯一标识符。
            //Name                  string, 获取或设置线程的名称。
            //Priority              获取或设置一个值,该值指示线程的调度优先级 。 Lowest < BelowNormal < Normal < AboveNormal < Highest>
            //ThreadState 获取一个值,该值包含当前线程的状态。 Unstarted、Sleeping、Running 等
            #endregion


            #region   方法名称 说明

            //GetDomain()       返回当前线程正在其中运行的当前域。
            //GetDomainId()     返回当前线程正在其中运行的当前域Id。
            //Start()           执行本线程。(不一定立即执行,只是标记为可以执行)
            //Suspend()         挂起当前线程,如果当前线程已属于挂起状态则此不起作用
            //Resume()          继续运行已挂起的线程。
            //Interrupt()       中断处于 WaitSleepJoin 线程状态的线程。
            //Abort()           终结线程
            //Join()            阻塞调用线程,直到某个线程终止。
            //Sleep()            把正在运行的线程挂起一段时间。
            #endregion


        }

        /// <summary>
        /// Semaphore负责协调线程,可以限制对某一资源访问的线程数量
        /// </summary>
        static void SemaphoreTest()
        {
            semLim.Wait();
            Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "开始执行");
            Thread.Sleep(2000);
            Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "执行完毕");
            semLim.Release();
        }

        //用于 Thread
        static void Run()
        {
            Thread.Sleep(700);
            Console.WriteLine("这是后台线程调用");
        }

        //用于 async/await
        static async Task<int> GetStrLengthAsync()
        {
            Console.WriteLine("GetStrLengthAsync方法开始执行");
            //此处返回的<string>中的字符串类型,而不是Task<string>
            string str = await GetString();
            Console.WriteLine("GetStrLengthAsync方法执行结束");
            return str.Length;
        }

        //用于 async/await
        static Task<string> GetString()
        {
            //Console.WriteLine("GetString方法开始执行")
            return Task<string>.Run(() =>
            {
                Thread.Sleep(2000);
                return "GetString的返回值";
            });
        }
    }

    //用于线程同步
    class BookShop
    {
        //剩余图书数量
        public int num = 1;
        private static readonly object locker = new object();
        public void Sale()
        {

            lock (locker)
            {
                int tmp = num;
                if (tmp > 0)//判断是否有书,如果有就可以卖
                {
                    Thread.Sleep(1000);
                    num -= 1;
                    Console.WriteLine("售出一本图书,还剩余{0}本", num);
                }
                else
                {
                    Console.WriteLine("没有了");
                }
            }
        }
    }

}
原文地址:https://www.cnblogs.com/LZXX/p/12761219.html