C# 多线程

本文详细探讨了C#中的多线程概念,包括进程与线程的区别,无参数和带参数子线程的创建,线程池和Task的使用,异步与同步操作,以及如何使用lock进行线程同步。还涉及了如何使用Abort()中断线程和不同方式启动线程的方法。
摘要由CSDN通过智能技术生成

C# 多线程

进程与线程

进程:进程就是一个应用程序,对电脑的各种资源的占用

线程:线程是程序执行的最小单位,任何操作都是线程完成的,线程依托进程存在的,一个进程可以有多个线程

无参数的子线程

 public static void ChildThread1()
        {
            Console.WriteLine("Child thread1 is starts");
        }

带参数的子线程

ChildThread2是带参数的子线程,所以要使用ParameterizedThreadStart类型的委托来指定子线程
如果使用的是不带参数的委托,不能使用带参数的Start方法运行线程,否则系统会抛出异常。
但使用带参数的委托,可以使用thread.Start()来运行线程,这时所传递的参数值为null。

特别注意:ParameterizedThreadStart委托的参数类型必须是object的

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Test
    {
        public static void ChildThread1()
        {
            Console.WriteLine("Child thread1 is starts");
        }
        //注意:ParameterizedThreadStart委托的参数类型必须是object的
        public static void ChildThread2(object obj)
        {
            Console.WriteLine("Child thread2 is starts,the parameter is {0}", obj);
        }
        public static void Main()
        {
            
            ThreadStart thread1 = new ThreadStart(ChildThread1); //通过ThreadStart委托指定子线程的方法
            ParameterizedThreadStart thread2 = new ParameterizedThreadStart(ChildThread2); //有参的委托
            Console.WriteLine("MainThread:Creating the child thread1");
            Console.WriteLine("MainThread:Creating the child thread2");
            Thread childThread1 = new Thread(thread1); //创建子线程1
            Thread childThread2 = new Thread(thread2);//创建子线程2
            childThread1.Start();    //运行子线程1
            childThread2.Start("子线程2的参数");//运行子线程2,传递参数,
            //如果使用的是不带参数的委托,不能使用带参数的Start方法运行线程,否则系统会抛出异常。
            //但使用带参数的委托,可以使用thread.Start()来运行线程,这时所传递的参数值为null。
            
            Console.ReadKey();
        }
    }
}

运行结果

在这里插入图片描述

销毁线程 Abort()

使用Abort()中止子线程.
通过抛出 threadabortexception 在运行时中止线程。这个异常不能被捕获,如果有 finally 块,控制会被送至 finally 块。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Test
    {
        public static void ChildThread1()
        {
            Console.WriteLine("Child thread1 is starts");
        }
        //注意:ParameterizedThreadStart委托的参数类型必须是object的
        public static void ChildThread2(object obj)
        {
            Console.WriteLine("Child thread2 is starts,the parameter is {0}", obj);
        }
        public static void ChildThread3()
        {
            try
            {
                Console.WriteLine("Child thread3 starts");
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(100);
                    Console.WriteLine(i);
                }
                Console.WriteLine("Child Thread3 Completed");
            }
            catch (ThreadAbortException e)
            {
                Console.WriteLine("Thread Abort Exception");
            }
            finally
            {
                Console.WriteLine("Couldn't catch the thread Exception");
            }
        }
        public static void Main()
        {
            ThreadStart thread3 = new ThreadStart(ChildThread3);
            Console.WriteLine("MainThread:Creating the child thread3");
            Thread thread = new Thread(thread3);
            thread.Start();
            //停止主线程1000
            Thread.Sleep(2000);
            Console.WriteLine("In Main: Aborting the Child thread");
            thread.Abort();
            Console.ReadKey();
        }
    }
}

运行结果

在这里插入图片描述

ThreadPool和Task

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    
    class Test
    {
        public static Thread t = null;
        public static void ChildThread1()
        {
            int i = 5;
            while (i > 0)
            {
                Console.WriteLine(string.Format("线程【1】的i:{0} ", i));
                Thread.Sleep(10);
                i--;
            }
            Console.WriteLine("线程【1】结束");

            //Console.WriteLine("Child thread1 is starts");
        }
        //注意:ParameterizedThreadStart委托的参数类型必须是object的
        public static void ChildThread2(object obj)
        {
            int i = 5;
            while (i > 0)
            {
                Console.WriteLine(string.Format("线程【2】的i:{0} ", i));
                Thread.Sleep(10);
                i--;
            }
            Console.WriteLine("线程【2】结束");
        }
        public static void ChildThread3()
        {
            int i = 5;
            while (i > 0)
            {
                Console.WriteLine(string.Format("线程【3】的i:{0} ", i));
                Thread.Sleep(10);
                i--;
            }
            Console.WriteLine("线程【3】结束");
        }
        
        public static void Main(string[] args)
        {
            t = new Thread(new ThreadStart(ChildThread1));
            t.Start();

            //用线程池
            ThreadPool.QueueUserWorkItem(ChildThread2, new object());

            //用Task方法创建
            System.Threading.Tasks.Task.Factory.StartNew(ChildThread3);
            Console.ReadLine();
        }
    }
}

运行结果

在这里插入图片描述
线程都是独立的,不会互相影响。

异步与同步

C# 5.0引入了异步方法(Async Methods)的概念,使得编写异步代码变得更加容易。异步方法使用async关键字标记,返回类型必须是Task或Task,方法中使用await关键字来等待异步操作完成。通过使用异步方法,可以在不阻塞主线程的情况下执行耗时操作,从而提高程序的并发性和响应性。示例如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{

    class Test
    {
        public static async Task Main(string[] args)
        {
            await DownloadWebsiteAsync();
            Console.ReadKey();
        }
        static async Task DownloadWebsiteAsync()
        {
            using (HttpClient client = new HttpClient())
            {
                string website = "https://www.example.com";
                string content = await client.GetStringAsync(website);
                Console.WriteLine("等待异步执行完成");
            }
        }
    }
}

运行结果

在这里插入图片描述

lock

如果你想控制多线程的线程的执行顺序,就需要用到lock

参考链接:https://blog.csdn.net/u012563853/article/details/124767902

单线程

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{

    class Test
    {
        static int a = 0;
        static int b = 0;
        private static object o = new object();
        static void Main(string[] args)
        {
            methodA();
            methodB();
            Console.ReadKey();
        }
        private static void methodA()
        {
            Console.WriteLine("我是A方法");
        }
        private static void methodB()
        {
            Console.WriteLine("我是B方法");
        }
        private static void methodC()
        {
            Console.WriteLine("我是C方法,是随机出现的");
        }
    }
}

这样是按顺序执行的,因为是单线程的,先执行methodA,再去执行methodB
在这里插入图片描述

运行结果

在这里插入图片描述

多线程

我们增加了多线程,就是让A和B方法同时执行,此时,结果就是不可控制的。有时候先执行B方法,有时候先执行A方法。先执行B方法。

在这里插入图片描述

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{

    class Test
    {
        static int a = 0;
        static int b = 0;
        private static object o = new object();
        static void Main(string[] args)
        {
            //methodA();
            //methodB();
            Thread t1 = new Thread(methodA);
            Thread t2 = new Thread(methodB);
            t1.Start();
            t2.Start();
            Console.ReadKey();
        }
        private static void methodA()
        {
            a = 1;
            Console.WriteLine("我是A方法,a=" + a);
            Thread.Sleep(2000); //暂停5秒
            b = 2;
            Console.WriteLine("我是A方法,b=" + b);
        }
        private static void methodB()
        {
            a++;
            Console.WriteLine("我是B方法,a=" + a);
            Thread.Sleep(1000); //暂停1秒
            b++;
            Console.WriteLine("我是B方法,b=" + b);
        }
        private static void methodC()
        {
            Console.WriteLine("我是C方法,是随机出现的");
        }
    }
}
运行结果

在这里插入图片描述
所以,我们可以使用lock去锁住代码段,锁住的这段代码,此时只能有一个线程去访问,只有等这个线程访问结束了,其他线程才能访问。

使用lock

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{

    class Test
    {
        static int a = 0;
        static int b = 0;
        private static object o = new object();
        static void Main(string[] args)
        {
            //methodA();
            //methodB();
            Thread t1 = new Thread(methodA);
            Thread t2 = new Thread(methodB);
            t1.Start();
            t2.Start();
            Console.ReadKey();
        }
        private static void methodA()
        {
            lock (o)
            {
                a = 1;
                Console.WriteLine("我是A方法,a=" + a);
                Thread.Sleep(2000); //暂停5秒
                b = 2;
                Console.WriteLine("我是A方法,b=" + b);
            }
        }
        private static void methodB()
        {
            lock (o)
            {
                a++;
                Console.WriteLine("我是B方法,a=" + a);
                Thread.Sleep(1000); //暂停1秒
                b++;
                Console.WriteLine("我是B方法,b=" + b);
            }
            
        }
        private static void methodC()
        {
            Console.WriteLine("我是C方法,是随机出现的");
        }
    }
}

在这里插入图片描述

运行结果

在这里插入图片描述
这样也是等效的:
在这里插入图片描述
Enter相当于进入这个代码块,Exit是退出这个代码块。当这个代码块再运行的时候,其他线程就不能访问。Monitor中的{}可以去掉,不影响。
在这里插入图片描述

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值