C#基础知识学习——多线程(Thread、Task、Sleep、Interrupt、线程同步处理locker、最大粒度、Monitor)(十八)

线程生命周期

新建(new 对象)
就绪(等待CPU调度)
运行(CPU正在运行)
阻塞(等待阻塞、同步阻塞等)
死亡(对象释放)

主线程

进程中第一个被执行得线程称为主线程,程序开始时,主线程自动创建。

线程属性介绍

属性描述
CurrentContext获取线程正在执行的当前上下文
CurrentCulture获取或设置当前线程的区域性
CurrentPrinciple获取或设置当前线程的负责人
CurrentThread获取当前正在运行的线程
CurrentUICulture获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源
ExecutionContext获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息
IsAlive获取一个值,该值指示当前线程的执行状态
IsBackground获取或设置一个值,该值指示某个线程是否为后台线程
IsThreadPoolThread获取一个值,该值指示线程是否属于托管线程池
ManagedThreadId获取当前托管线程的唯一标识符
Name获取或设置线程的名称
Priority获取或设置一个值,该值指示线程的调度优先级
ThreadState获取一个值,该值包含当前线程的状态

Thread.CurrentThread.Priority: 线程优先级,设置为高优先级的线程并不会一定在低优先级的线程之前执行,只是增加了优先执行的概率。

         public static void Test()
        {
            Thread thread = Thread.CurrentThread;//获取当前执行得线程对象
            thread.Name = "MainThread";

            Console.WriteLine("this is {0},ID={1},优先级:{2}", thread.Name, Thread.CurrentThread.ManagedThreadId
                ,Thread.CurrentThread.Priority);
        }    

线程创建

创建线程方法:

Thread

不带参数的方法创建线程

Thread thread = new Thread(new ThreadStart(CreadThread));

带参数的方法创建线程

Thread thread=new Thread(new ParameterizedThreadStart(CreadThread!));
一般方法参数只能为object

     public class ThreadCreadMethod
    {
        
        public static void CreadMethod01()
        {
            //不带参数的方法创建线程
            Thread thread = new Thread(new ThreadStart(CreadThread));
            thread.Name = "生出小兵逻辑";
            thread.Start();
        }
        ///带参数的线程
        public static void CreadMethod02()
        {
            Thread thread=new Thread(new ParameterizedThreadStart(CreadThread!));
            thread.Name = "生出野怪";
            thread.Start(thread.Name);
        }
        public static void CreadThread()
        {
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine(Thread.CurrentThread.Name+":"+i);
            }
        }
        /// <summary>
        /// 带参数
        /// </summary>
        public static void CreadThread(object para)
        {
            Thread.CurrentThread.Name = para.ToString();
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine(Thread.CurrentThread.Name + ":" + i);
            }
        }
    }
    public void Test()
    {
        ThreadCreadMethod.CreadMethod01();
        ThreadCreadMethod.CreadMethod02();
}

Task

直接通过task创建线程
通过factory创建线程
通过Task.run创建线程
/// <summary>
        /// 直接通过task创建线程
        /// </summary>
        public static void CreadMethod01()
        {
            var task = new Task(() =>
            {
                Console.WriteLine("代码模块  或   调用方法");
                CreateTask();
            });
            task.Start();
        }
        /// <summary>
        /// 通过factory创建线程
        /// </summary>
        public static void CreadMethod02()
        {
            Task.Factory.StartNew(() =>
            {
                Console.WriteLine("通过factory创建线程 ====代码模块  或   调用方法");
                CreateTask();
            });
        }
        /// <summary>
        /// 通过Task.run创建线程  比较常用[这种方式会放到线程池,重用线程]
        /// </summary>
        public static void CreadMethod03()
        {
            Task.Run(() =>
            {
                Console.WriteLine("通过Task.run创建线程 ====代码模块  或   调用方法");
                CreateTask();
            });
        }
         public static void CreateTask()
        {
            Thread.CurrentThread.Name = "Task线程一";
            for (int i = 0; i < 20; i++)
            {
                Console.WriteLine(Thread.CurrentThread.Name + ":" + i);
            }            
        }
    }

前台线程与后台线程

默认情况下,创建的线程是前台线程。只要前台线程中的任何一个正在运行,它就可以使应用程序保持活动状态,而后台线程则不会。一旦所有前台线程完成,应用程序结束,所有仍在运行的后台线程终止。
设置IsBackground为true,即为后台线程。


    public class BackGroundClassTest
    {
        public static void TestBackGround()
        {
            ///演示前台线程
            BackGroundTest backGroundTest = new BackGroundTest(10);
            ///创建前台线程
            Thread fthread = new Thread(new ThreadStart(backGroundTest.RunLoop));
            fthread.Name = "前台线程";

            ///演示后台线程
            BackGroundTest backGroundTest1 = new BackGroundTest(20);
            ///创建前台线程
            Thread bthread1 = new Thread(new ThreadStart(backGroundTest1.RunLoop));
            bthread1.Name = "后台线程";
            bthread1.IsBackground= true;

            fthread.Start();
            bthread1.Start();
        }
    }
    class BackGroundTest
    {
        private int Count;
        public BackGroundTest(int count)
        { 
        this.Count = count;
        }
        public void RunLoop()
        {
            string threadname = Thread.CurrentThread.Name;
            for (int i = 0; i < Count; i++)
            {
                Console.WriteLine($"{threadname}计数:{i}");
                Thread.Sleep( 10 );
            }
            Console.WriteLine($"{threadname}完成计数");
        }
    }
    
 Console.WriteLine("主线程开始");
 BackGroundClassTest.TestBackGround();
 Console.WriteLine("主线程结束");

当 bthread1.IsBackground= true时,即为后台线程时。运行结果为:
在这里插入图片描述

当 bthread1.IsBackground= false时,即为前台线程时。运行结果为:
在这里插入图片描述

线程常用方法

sleep

举个例子:访问资源失败时,需要等待一段时间继续访问,这个时候可以调用sleep方法

 public class SleepClass1
    {
        public static void Test()
        {
            Console.WriteLine("Enter Main");
            Thread thread1 = new Thread(new ThreadStart(Counter));

            Thread thread2 = new Thread(new ThreadStart(Counter2));
            thread2.Priority= ThreadPriority.Highest;

            thread1.Start();
            thread2.Start();

            Console.WriteLine("EXIT Main");
        }
        public static void Counter()
        {
            Console.WriteLine("Enter Counter1");
            for (int i = 0; i < 50; i++)
            {
                Console.Write(i + "  ");
                if (i==10)
                {
                    Console.WriteLine();
                    Thread.Sleep(1000);
                }
            }
            Console.WriteLine("Exit Counter1");
        }
        public static void Counter2()
        {
            Console.WriteLine("Enter Counter2");
            for (int i = 51; i < 100; i++)
            {
                Console.Write(i + "  ");
                if (i ==70)
                {
                    Console.WriteLine();
                    Thread.Sleep(1000);
                }
            }
            Console.WriteLine("Exit Counter2");
        }
    }

运行结果
在这里插入图片描述

Interrupt

使用线程的Interrupt方法只可以中断处于 WaitSleepJoin 状态的线程,当线程状态不再为 WaitSleepJoin时,线程将恢复执行。

public class InterruptClass1
    {
       static Thread Threadsleep;
        static Thread Threadwork;
        public static void test()
        {
            Threadsleep = new Thread(new ThreadStart(SleepingThread));
            Threadwork = new Thread(new ThreadStart(AwakeThread));

            Threadsleep.Start();
            Threadwork.Start();
        }
        public static void SleepingThread()
        {
            for (int i = 0; i < 50; i++)
            {
                Console.Write(i + " ");
                if (i == 10 || i == 20 || i == 30)
                {
                    Console.Write("sleeping-----" + i);
                    try
                    {
                        Thread.Sleep(20);
                    }
                    catch (ThreadInterruptedException er)
                    {
                        Console.WriteLine(er.Message);
                    }

                }
            }
        }
        /// <summary>
        /// 线程状态为ThreadState.WaitSleepJoin时,才能调用Interrupt方法
        /// </summary>
        public static void AwakeThread()
        {
            for (int i = 51; i < 100; i++)
            {
                Console.Write(i + " ");
                if (Threadsleep.ThreadState==ThreadState.WaitSleepJoin)
                {
                    Console.WriteLine(" Threadsleep is  Interrupt");
                    Threadsleep.Interrupt();

                }
            }
        }
    }

在这里插入图片描述

Join

Join方法主要用来阻塞调用线程,直到某个线程终止或经过了指定时间为止,使得线程变得有序起来

    public class JoinClass
    {
        public static void Test()
        {
            Thread thread = new Thread(ThreadMethod!);
            thread.Name = "线程A";

            Thread thread0 = new Thread(ThreadMethod!);
            thread0.Name = "线程B";


            thread.Start();
            thread.Join();
            thread0.Start();
            thread0.Join();

            for (int i = 0; i <= 3; i++)
            {
                Console.WriteLine($"我是主线程,循环了{i}次");
            }
        }

        public static void ThreadMethod(object parameter)
        {
            for (int i = 0; i <= 3; i++)
            {
                Console.WriteLine($"我是{Thread.CurrentThread.Name}循环了{i}次");
                Thread.Sleep(300);
            }
        }
     
    }

未用join方法
在这里插入图片描述

用join方法
在这里插入图片描述

线程同步

多个线程使用同一资源,会出现数据竞争问题,因而需要线程同步来解决这一问题:locker、最大粒度、Monitor

未使用线程同步

     public class ThreadSync
    {
        public static int Counter = 0;
         /// <summary>
        /// 线程未同步---存在数据竞争问题
        /// </summary>
        public static void TestNoSyncThread()
        {
            Thread thread1 = new Thread(() =>
            {
                for (int i = 0; i < 1000; i++)
                {
                    Counter++;
                    Thread.Sleep(1);
                }
            });
            thread1.Start();

            Thread thread2 = new Thread(() =>
            {
                for (int i = 0; i < 1000; i++)
                {
                    Counter++;
                    Thread.Sleep(1);
                }
            });
            thread2.Start();

            Thread.Sleep(30000);
            Console.WriteLine("线程未同步:"+Counter);
             
        }
     }

处理结果:出现数据竞争,数据结果出错
在这里插入图片描述

Locker

使用locker同步

 public class ThreadSync
    {
     public static int Counter_locker = 0;
       /// <summary>
        /// 线程使用locker同步
        /// </summary>
        public static void TestSyncThread_locker()
        {
            Thread thread1 = new Thread(() =>
            {
                for (int i = 0; i < 1000; i++)
                {
                    //同步块
                    lock (locker)
                    {
                        Counter_locker++;
                    }
                    
                    Thread.Sleep(1);
                }
            });
            thread1.Start();

            Thread thread2 = new Thread(() =>
            {
                for (int i = 0; i < 1000; i++)
                {
                    //同步块
                    lock (locker)
                    {
                        Counter_locker++;
                    }
                  
                    Thread.Sleep(1);
                }
            });
            thread2.Start();

            Thread.Sleep(30000);
            Console.WriteLine("线程使用locker同步:" + Counter_locker); 
        }
        }

处理结果:
在这里插入图片描述

最大粒度

[MethodImpl(MethodImplOptions.Synchronized)]

     public class ThreadSync
    {
      static int money = 1000;
        /// <summary>
        /// 线程同步使用最大粒度
        /// </summary>
        public static void TestSyncThread_Imp()
        {
            Thread thread1 = new Thread(() =>
            {
                for (int i = 0; i < 200; i++)
                {
                    同步块
                    //lock (locker)
                    //{
                    //    FetchMoney("thread1");
                    //}
                    FetchMoney("thread1"); 
                    Thread.Sleep(1);
                }
            });
            thread1.Start();

            Thread thread2 = new Thread(() =>
            {
                for (int i = 0; i < 200; i++)
                {
                    同步块
                    //lock (locker)
                    //{
                    //    FetchMoney("thread2");
                    //}

                    FetchMoney("thread2"); 
                    Thread.Sleep(1);
                }
            });
            thread2.Start();

            Thread.Sleep(30000);
            Console.WriteLine("线程使用最大粒度同步:" + Counter_locker);
        }
        /// <summary>
        /// 使用最大粒度同步线程
        /// </summary>
        /// <param name="name"></param>
        [MethodImpl(MethodImplOptions.Synchronized)]
        public static void FetchMoney(string name)
        {
            Console.WriteLine("当前余额" + money);
            int yu = money - 1;
            Console.WriteLine(name+"取钱");
            money = yu;
            Console.WriteLine(name+"取完了,剩余"+money);
        }
  }

处理结果:
在这里插入图片描述

Monitor

 public class ThreadSync
    {
       static int money = 1000;
       /// <summary>
        /// 必须为静态、object类型
        /// </summary>
        public static object locker=new object();
      /// <summary>
        /// 使用mointor同步线程
        /// </summary>
        /// <param name="name"></param>        
        public static void FetchMoney_mointor(string name)
        {
            //等待没有人锁定locker对象,就锁定它,然后继续执行
            Monitor.Enter(locker);
            try
            {
                Console.WriteLine("当前余额" + money);
                int yu = money - 1;
                Console.WriteLine(name + "取钱");
                money = yu;
                Console.WriteLine(name + "取完了,剩余" + money);
            }
           finally
            {

                Monitor.Exit(locker);
            }
            
        }
        public static void TestSyncThread_Imp()
        {
            Thread thread1 = new Thread(() =>
            {
                for (int i = 0; i < 200; i++)
                { 
                   FetchMoney_mointor("thread1");
                    Thread.Sleep(1);
                }
            });
           
            Thread thread2 = new Thread(() =>
            {
                for (int i = 0; i < 200; i++)
                { 
                   FetchMoney_mointor("thread2");
                    Thread.Sleep(1);
                }
            });
            thread2.Start();
            thread1.Start();
            thread1.Join();
            thread2.Join();
            
            Console.WriteLine("线程使用Monitor同步:" + money);
        }
 }

结果:
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值