广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >c#多线程之线程基础
  • 534
分享到

c#多线程之线程基础

2024-04-02 19:04:59 534人浏览 安东尼
摘要

目录一、简介二、创建线程三、暂停线程四、线程等待五、终止线程六、检测线程状态七、线程优先级八、前台线程和后台线程九、向线程传递参数十、使用C# Lock 关键字十一、使用Monito

一、简介

1.为了防止一个应用程序控制CPU而导致其他应用程序和操作系统本身永远被挂起这一可能情况,操作系统不得不使用某种方式将物理计算分割为一些虚拟的进程,并给予每个执行程序一定量的计算能力。此外操作系统必须始终能够优先访问CPU,并能调整不同程序访问CPU的优先级。线程正式这一慨念的实现。

2.多线程优缺点:
多线程优点:可以同时执行多个计算任务,有可能提高计算机的处理能力,使得计算机每秒能执行越来越多的命令
多线程缺点:消耗大量的操作系统资源。多个线程共享一个处理器将导致操作系统忙于管理这些线程,而无法运行程序。

二、创建线程

class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(PrintNumbers));//无参数的委托,把方法的引用当做参数
            t1.Start();

            Thread t2 = new Thread(new ParameterizedThreadStart(PrintNumbers));//有参数的委托,把方法的引用当做参数
            t2.Start(10);
            Console.ReadLine();
        }

        static void PrintNumbers()
        {
            Console.WriteLine("1.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i);
            }
        }

        //注意:要使用ParameterizedThreadStart,定义的参数必须为object
        static void PrintNumbers(object count)
        {
            Console.WriteLine("2.Starting...");
            for (int i = 0; i < Convert.ToInt32(count); i++)
            {
                Console.WriteLine(i);
            }
        }
    }
}

注释:

1.我们只需指定在不同线程运行的方法名,而C#编译器会在后台创建这些对象。

2.要使用ParameterizedThreadStart,定义的参数必须为object类型。

三、暂停线程

class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(PrintNumbersWithDelay);
            t1.Start();
            PrintNumbers();
            Console.ReadLine();
        }

        static void PrintNumbers()
        {
            Console.WriteLine("1.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("In 1.Starting: " + i);
            }
        }

        static void PrintNumbersWithDelay()
        {
            Console.WriteLine("2.Starting...");
            for (int i = 0; i < 10; i++)
            {
                //var a = TimeSpan.FromSeconds(2);
                Thread.Sleep(TimeSpan.FromSeconds(2));//暂停两秒
                Console.WriteLine("In 2.Starting: " + i);
            }
        }
    }

注释:使用Thread.Sleep(TimeSpan.FromSeconds(2));暂停线程一段时间

四、线程等待

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting...");
            Thread t = new Thread(PrintNumbersWithDelay);
            t.Start();
            t.Join();   //使用Join等待t完成后,再向下执行PrintNumbers,如果注释掉输出明显不同
            PrintNumbers();
            Console.WriteLine("Thread Complete");
            Console.ReadLine();
        }

        static void PrintNumbers()
        {
            Console.WriteLine("1.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("In 1.Starting:" + i);
            }
        }

        static void PrintNumbersWithDelay()
        {
            Console.WriteLine("2.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(2));
                Console.WriteLine("In 2.Starting:" + i);
            }
        }
    }

注释:使用t.Join();   等待t完成。

五、终止线程

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting Program...");
            Thread t1 = new Thread(PrintNumbersWithDelay);
            t1.Start();
            Thread.Sleep(TimeSpan.FromSeconds(7));//此时t1线程会执行7秒
            t1.Abort();    //使用Abort()终止线程
            Console.WriteLine("Thread t1 has been aborted");
            Thread t2 = new Thread(PrintNumbers);
            t2.Start();
            Console.ReadLine();
        }

        static void PrintNumbers()
        {
            Console.WriteLine("1.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("In 1.Starting:" + i);
            }
        }
        static void PrintNumbersWithDelay()
        {
            Console.WriteLine("2.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(2));
                Console.WriteLine("In 2.Starting:" + i);
            }
        }
    }

注释:使用Thread实例的Abort方法终止线程。

六、检测线程状态

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Start Program...");
            Thread t1 = new Thread(PrintNumbersWithStatus);
            Thread t2 = new Thread(DoNothing);
            Console.WriteLine("t1 status:" + t1.ThreadState.ToString());//获取实例线程状态
            t2.Start();
            t1.Start();
            for (int i = 0; i < 30; i++)
            {
                Console.WriteLine("t1 status:" + t1.ThreadState.ToString() + "\t" + "t2 status:" + t2.ThreadState.ToString());
            }
            Thread.Sleep(TimeSpan.FromSeconds(7));
            t1.Abort();
            Console.WriteLine("thread t1 has been aborted");
            Console.WriteLine("t1 status:" + t1.ThreadState.ToString());
            Console.WriteLine("t2 status:" + t2.ThreadState.ToString());
            Console.ReadLine();
        }

        private static void PrintNumbersWithStatus()
        {
            Console.WriteLine("1.Starting...");
            Console.WriteLine("In 1.Starting t1 status:" + Thread.CurrentThread.ThreadState.ToString());//获取当前线程状态
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(2));
                Console.WriteLine("In 1.Starting:" + i);
            }
        }

        private static void DoNothing()
        {
            Thread.Sleep(TimeSpan.FromSeconds(2));
            Console.WriteLine("t2 Console...");
        }
    }

注释:使用Thread.ThreadState获取线程的运行状态。ThreadState是一个C#枚举。谨记:不要在程序中使用线程终止,否则可能会出现意想不到的结果

七、线程优先级

class Program
    {
        static void Main(string[] args)
        {
            //让操作系统的所有线程运行在多个CPU核心上
            Console.WriteLine($"Current thread priority: {Thread.CurrentThread.Priority}");
            Console.WriteLine("Running on all cores available");//获取实例线程状态
            RunThreads();

            Thread.Sleep(TimeSpan.FromSeconds(2));
            Console.WriteLine("Running on a single Core");
            //让操作系统的所有线程运行在单个CPU核心上
            Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
            RunThreads();
            Console.ReadLine();
        }

        private static void RunThreads()
        {
            var sample = new ThreadSample();
            var t1 = new Thread(sample.CountNumbers);
            t1.Name = "Thread One";
            var t2 = new Thread(sample.CountNumbers);
            t2.Name = "Thread Two";

            t1.Priority = ThreadPriority.Highest;//使用Priority设置线程的优先级
            t2.Priority = ThreadPriority.Lowest;
            t1.Start();
            t2.Start();//此处t2优先级低于t1,t2等待t1释放资源。

            Thread.Sleep(TimeSpan.FromSeconds(2));
            sample.Stop();
        }
    }

    class ThreadSample
    {
        private bool _isStopped = false;
        public void Stop()
        {
            _isStopped = true;
        }
        public void CountNumbers()
        {
            long counter = 0;
            while (!_isStopped)
            {
                counter++;
            }
            Console.WriteLine($"{Thread.CurrentThread.Name} with {Thread.CurrentThread.Priority} priority has a count={counter.ToString("N0")}");
        }
    }

注释:单核执行多线程耗费的时间比多核的多很多。

八、前台线程和后台线程

class Program
    {
        static void Main(string[] args)
        {
            var sampleForground = new ThreadSample(10);
            var sampleBackground = new ThreadSample(20);
            var t1 = new Thread(sampleForground.CountNumbers);//方法的引用
            t1.Name = "ForegroundThread"; //没有明确声明的均为前台线程

            var t2 = new Thread(sampleBackground.CountNumbers);
            t2.Name = "BackgroundThread";
            t2.IsBackground = true;   //设置为后台线程

            t1.Start();
            t2.Start();
            Console.ReadLine();

        }
    }
    class ThreadSample
    {
        private readonly int _iteration;

        public ThreadSample(int iteration)
        {
            _iteration = iteration;
        }

        public void CountNumbers()
        {
            for (int i = 0; i < _iteration; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
            }
        }
    }

注释:进程会等待所有的前台线程完成后再结束工作,但是如果只剩下后台线程,则会直接结束工作。

九、向线程传递参数

class Program
    {
        static void Main(string[] args)
        {
            ThreadSample sample = new ThreadSample(5);
            Thread t1 = new Thread(sample.CountNumbers);
            t1.Name = "ThreadOne";
            t1.Start();
            t1.Join();
            Console.WriteLine("--------------------------");

            Thread t2 = new Thread(Count);
            t2.Name = "ThreadTwo";
            t2.Start(3);
            t2.Join();
            Console.WriteLine("--------------------------");

            //使用lambda表达式引用另一个C#对方的方式被称为闭包。当在lambda表达式中使用任何局部变量时,C#会生成一个类,并将该变量作为该类的一个属性,但是我们无须定义该类,C#编译器会自动帮我们实现
            Thread t3 = new Thread(() => CountNumbers(5));
            t3.Name = "ThreadThree";
            t3.Start();
            t3.Join();
            Console.WriteLine("--------------------------");

            int i = 10;
            Thread t4 = new Thread(() => PrintNumber(i));

            i = 20;
            Thread t5 = new Thread(() => PrintNumber(i));
            t4.Start();
            t5.Start();
            //t4, t5都会输出20, 因为t4,t5没有Start之前i已经变成20了
            Console.ReadKey();
        }

        static void Count(object iterations)
        {
            CountNumbers((int)iterations);
        }

        static void CountNumbers(int iterations)
        {
            for (int i = 1; i <= iterations; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
            }
        }

        static void PrintNumber(int number)
        {
            Console.WriteLine(number);
        }
    }
    class ThreadSample
    {
        private readonly int _iteration;

        public ThreadSample(int iteration)
        {
            _iteration = iteration;
        }

        public void CountNumbers()
        {
            for (int i = 1; i <= _iteration; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
            }
        }
    }

十、使用C# Lock 关键字

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Incorrect Counter");
            Counter c1 = new Counter();
            var t1 = new Thread(() => TestCounter(c1));
            var t2 = new Thread(() => TestCounter(c1));
            var t3 = new Thread(() => TestCounter(c1));
            t1.Start();
            t2.Start();
            t3.Start();
            t1.Join();
            t2.Join();
            t3.Join();
            Console.WriteLine($"Total Count: {c1.Count}");
            Console.WriteLine("------------------------");

            //使用LOCK关键字,Count同一时刻只允许一个线程访问
            Console.WriteLine("Correct counter");
            CounterWithLock c2 = new CounterWithLock();
            t1 = new Thread(() => TestCounter(c2));
            t2 = new Thread(() => TestCounter(c2));
            t3 = new Thread(() => TestCounter(c2));
            t1.Start();
            t2.Start();
            t3.Start();
            t1.Join();
            t2.Join();
            t3.Join();
            Console.WriteLine($"Total count:{c2.Count}");
            Console.ReadLine();
        }

        static void TestCounter(CounterBase c)
        {
            for (int i = 0; i < 100000; i++)
            {
                c.Increment();
                c.Decrement();
            }
        }

        //子类
        class Counter : CounterBase
        {
            public int Count { get; private set; }
            //重写基类方法
            public override void Decrement()
            {
                Count--;
            }

            public override void Increment()
            {
                Count++;
            }
        }

        //子类
        class CounterWithLock : CounterBase
        {
            private readonly object _asyncRoot = new object();
            public int Count { get; private set; }
            //重写基类方法
            public override void Decrement()
            {
                lock (_asyncRoot)
                {
                    Count--;
                }
            }

            public override void Increment()
            {
                lock (_asyncRoot)
                {
                    Count++;
                }
            }
        }

        //基类
        abstract class CounterBase
        {
            public abstract void Increment();

            public abstract void Decrement();
        }
    }
    class ThreadSample
    {
        private readonly int _iteration;

        public ThreadSample(int iteration)//构造函数
        {
            _iteration = iteration;
        }

        public void CountNumbers()
        {
            for (int i = 1; i <= _iteration; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
            }
        }
    }

注释:不加锁,得出的结果不确定,竞争条件下很容易出错。加锁得出的结果是正确的,但是性能受到了影响

十一、使用Monitor类锁定资源

class Program
    {
        static void Main(string[] args)
        {
            object lock1 = new object();
            object lock2 = new object();
            new Thread(() => LockTooMuch(lock1, lock2)).Start();
            lock (lock2)
            {
                Thread.Sleep(1000);
                Console.WriteLine("Monitor.TryEnter allows not to get stuck, returning false after a specified timeout is elapsed");
               
                //直接使用Monitor.TryEnter, 如果在第二个参数之前还未获取到lock保护的资源会返回false
                if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5)))
                {
                    Console.WriteLine("Acquired a protected resource successfully");
                }
                else
                {
                    Console.WriteLine("Timeout acquiring a resource");
                }
            }
            new Thread(() => LockTooMuch(lock1, lock2)).Start();
            Console.WriteLine("-----------------------------");
         
            
        }

        static void LockTooMuch(object lock1, object lock2)
        {
            lock (lock1)
            {
                Thread.Sleep(1000);
                lock (lock2);
            }
        }
    }

注释:Monitor.TryEnter在指定的时间内尝试获取指定对象上的排他锁

十二、处理异常

class Program
    {
        static void Main(string[] args)
        {
            Thread t = new Thread(FaultyThread);
            t.Start();
            t.Join();
            try
            {
                t = new Thread(BadFaultyThread);
                t.Start();
            }
            catch (Exception ex)
            {
                Console.WriteLine("We won't get here");
            }
        }
        static void BadFaultyThread()
        {
            Console.WriteLine("Starting a bad faulty thread.....");
            Thread.Sleep(TimeSpan.FromSeconds(2));
            //这个异常主线程无法捕捉到,因为是在子线程抛出的异常。需要在子线程中加入try...catch捕获异常
            throw new Exception("Boom!");
        }
        static void FaultyThread()
        {
            try
            {
                Console.WriteLine("Starting a faulty thread...");
                Thread.Sleep(TimeSpan.FromSeconds(1));
                throw new Exception("Boom!");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Exception handled: {ex.Message}");
            }
        }
    }

到此这篇关于c#多线程之线程基础的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: c#多线程之线程基础

本文链接: https://www.lsjlt.com/news/146375.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c#多线程之线程基础
    目录一、简介二、创建线程三、暂停线程四、线程等待五、终止线程六、检测线程状态七、线程优先级八、前台线程和后台线程九、向线程传递参数十、使用C# Lock 关键字十一、使用Monito...
    99+
    2022-11-13
  • C#多线程开发实战记录之线程基础
    目录前言线程基础 1、创建线程2、暂停线程3、线程等待4、线程终止C#中的lock关键字总结前言 最近由于工作的需要,一直在使用C#的多线程进行开发,其中也遇到了很多问题,但也都解决...
    99+
    2022-11-12
  • C#多线程学习之基础入门
    目录同步方式异步多线程方式异步多线程优化异步回调异步信号量异步多线程返回值异步多线程返回值回调线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进...
    99+
    2022-11-12
  • C#多线程系列之任务基础(一)
    目录多线程编程多线程编程模式探究优点任务操作两种创建任务的方式Task.Run() 创建任务取消任务父子任务任务返回结果以及异步获取返回结果捕获任务异常全局捕获任务异常多线程编程 多...
    99+
    2022-11-13
  • C#多线程系列之任务基础(二)
    目录判断任务状态再说父子任务组合任务/延续任务复杂的延续任务并行(异步)处理任务并行(同步)处理任务并行任务的 Task.WhenAny并行任务状态循环中值变化问题定时任务 Task...
    99+
    2022-11-13
  • C#多线程系列之任务基础(三)
    目录TaskAwaiter延续的另一种方法另一种创建任务的方法实现一个支持同步和异步任务的类型Task.FromCanceled()如何在内部取消任务Yield 关键字补充知识点Ta...
    99+
    2022-11-13
  • C# 异步多线程入门基础
    目录进程、线程1. 进程 2. 线程 分时、分片同步、异步异步、多线程异步多线程效率多线程无序性扩展异步多线程版本下一篇:C# 异步多线程入门到精通之Thread篇 进程、线程 1....
    99+
    2022-11-12
  • C#多线程之线程锁
    目录一、Mutex类二、Mutex的用途三、Semaphore信号量1、简介2、初始化3、WaitOne()和Release()四、Monitor类典型的生产者与消费者实例五、Loc...
    99+
    2022-11-13
  • Java多线程基础
    目录一、线程二、创建多线程的方式1、继承Thread类实现多线程2、实现Runnable接口方式实现多线程3、Callable接口创建线程三、线程的生命周期与状态四、线程的执行顺序1...
    99+
    2022-11-12
  • java——多线程基础
    目录多线程使用场景:线程和进程区别:创建线程的方式:Thread类的有关方法:线程的同步:模拟火车站售票程序线程的同步:synchronized1. 同步代码块:2. synchro...
    99+
    2022-11-12
  • python多线程基础
    一、python多线程基础    python多线程主要涉及两个类:thread和threading,后者实际是对前者的封装,由于threading提供了更完善的锁机制,运用场景更多,重点学习了这个类的使用。threading.Thread...
    99+
    2023-01-31
    多线程 基础 python
  • JAVA多线程线程安全性基础
    目录线程安全性什么是线程安全的代码什么是线程安全性 总结线程安全性 一个对象是否需要是线程安全的,取决于它是否被多个线程访问,而不取决于对象要实现的功能 什么是线程安全的代码 核心:...
    99+
    2022-11-12
  • C#多线程之线程同步
    一、前言 我们先来看下面一个例子: using System; using System.Threading; namespace ThreadSynchDemo { cl...
    99+
    2022-11-13
  • C#多线程之线程池(ThreadPool)
    一、简介 前面介绍了平时用到的大多数的多线程的例子,但在实际开发中使用的线程往往是大量的和更为复杂的,这时,每次都创建线程、启动线程。从性能上来讲,这样做并不理想(因为每使用一个线程...
    99+
    2022-11-13
  • py基础---多线程、多进程、协程
    目录 Python基础__线程、进程、协程 1、什么是线程(thread)? 2、什么是进程(process)? 3、进程和线程的区别...
    99+
    2023-01-31
    多线程 进程 基础
  • C#多线程之线程同步WaitHandle
    一、引言 在前面的文章中,我们是使用“锁”的方式实现了线程间的通信,这种通信方式比较笨重。除了锁之外,.NET中还提供了一些线程间更自由通讯的工具,他们提供了...
    99+
    2022-11-13
  • C#多线程之线程通讯(AutoResetEvent)
    一、简介 我们在线程编程的时候往往会涉及到线程的通信,通过信号的接受来进行线程是否阻塞的操作。AutoResetEvent 允许线程通过发信号互相通信。通常,此通信涉及线程需要独占访...
    99+
    2022-11-13
  • C#多线程系列之线程池
    目录线程池ThreadPool 常用属性和方法线程池说明和示例线程池线程数线程池线程数说明不支持的线程池异步委托任务取消功能计时器线程池 线程池全称为托管线程池,线程池受 .NET ...
    99+
    2022-11-13
  • 【Java】Java多线程编程基础
    文章目录 1. 进程与线程1.1 进程与线程的基本认识1.1.1 进程(Process)1.1.2 线程(Thread) 1.2 为什么会有线程1.2.1 以看视频为例 2. ...
    99+
    2023-10-03
    java python 开发语言
  • Java多线程——基础概念
    目录java多线程并发与并行:多线程使用场景:创建线程的方式:Thread类的有关方法:线程的同步:       ...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作