C#多线程

文章介绍了C#中多线程的创建方式,包括Thread、ThreadStart、ParameterizedThreadStart和ThreadPool,以及线程抢占、线程锁和Task的使用,还讨论了异步编程的async/await特性。
摘要由CSDN通过智能技术生成
1)多线程
进程 主线程和分线程关系

一个程序就是一个进程,然而进程里面包含若干个线程,而每个进程里面都有一个(可以说必须要有一个)线程,这个线程就是主线程,然而主线程有一天发现自己的工作太多了,在规定的时间内完不成工作,这时候他就召唤了一个小弟(子线程)帮他,他给小弟分配了一些任务,当小弟做完了分配给他的任务后,他就把小弟赶走了!这就是主线程和子线程。 1)如果主线程遇到了 繁重的任务 可以开辟分线程来执行任务 从而不影响主线程的执行

2.C# 到5.0 之前一共有4种创建线程的方式:

1.Thread

含义:自己创建的独立的线程, 优先级高,需要使用者自己管理

//线程无参无返回值的委托
//创建分线程1 要执行的任务(委托)
ThreadStart childref = new ThreadStart(ProgramMothod);//委托要引入的方法名
 //创建分线程实例对象
Thread childThread = new Thread(childref);
 childThread.Name = "分线程1";
//执行分线程
childThread.Start();
 //以下输出在主线程中执行
Console.WriteLine("1");
Console.WriteLine("2");
Console.WriteLine("3");
Console.WriteLine("4");
Thread.CurrentThread.Name = "主线程";
​
//创建线程2
ThreadStart childref = () => {
 Console.WriteLine("繁重的任务2");
};
Thread thread2 = new Thread(childref);
thread2.Start();
​
//创建线程3
Thread thread3 = new Thread(() =>
{
Console.WriteLine("繁重的任务3");
 //线程休眠  单位毫秒
Thread.Sleep(2000);
Console.WriteLine("繁重的任务33");
});
​
​
​
//线程有一个参数无返回值的委托
ParameterizedThreadStart parameterizedThreadStart = new ParameterizedThreadStart(ProgramMothod2);//ProgramMothod2是一个有一个参数无返回值的方法
Thread thread5 = new Thread(parameterizedThreadStart);
 //委托的方法 实际参数 是.Start的重载
thread5(传入的参数);
​
 //线程执行 有一个参数的委托2
Thread thread6 = new Thread(e => {
​
    Console.WriteLine("繁重的任务5{0}", e);
});
thread6.Start(400);
​
  //线程阻塞 t.Join()
 Thread t = new Thread(() => 
 { 
  for (int i = 0; i < 1000; i++) Console.Write("y"); 
 });
 Thread t1 = new Thread(() => {
 // t.Join();
 for (int i = 0; i < 1000; i++)
 Console.Write("x");
 });
 t.Start();
 t.Join();//主线程阻塞 分线程t也会被诸塞(因为t.start()的调用发生在join前)
 t1.Start();
 Console.WriteLine("Thread t has ended!");
​
       //上面线程用到的方法
        //在分线程中执行
        public static void ProgramMothod()
        {
            Console.WriteLine("繁重的任务1");
            //
            Console.WriteLine(Thread.CurrentThread.Name);
        }
​
        //在主线程中执行
        public static void ProgramMothod1()
        {
​
            Console.WriteLine(Thread.CurrentThread.Name);
​
        }
​
​
        //有一个object类型参数  无返回值方法
        public static void ProgramMothod2(object a)
        {
​
            Console.WriteLine("繁重的任务5{0}", a);
​
        }
2)线程抢占

1.如果两个线程同时对某个资源进行同时访问、 就可能出现 线程抢占

可以用线程锁解决

 static bool done;
  static readonly object locker = new object();  //线程锁对象
​
Main方法中:
            //开启分线程执行go方法
            Thread thread = new Thread(Go);
            thread.Name = "分线程1";   
            Thread thread1 = new Thread(Go);
            thread1.Name = "分线程2";
            thread1.Start();    //按代码的执行顺序时先启动thread1线程,那么必须等到thread1线程执行完才能执行下面的代码
            thread.Start();
             //设置当前主线程的名字
            Thread.CurrentThread.Name = "主线程";
​
//
  static void Go()
        {
            //lock线程锁 如果某个线程进入方法内时 会锁定方法  
            //直到当前线程执行完毕此方法时 ,后续的线程才能进入方法执行代码
      
            //(标识对象)
            lock (locker)//那个分线程先抢到线程,其他的线程就必须等到在这个线程结束之后才能执行
            {
​
                if (!done)
                {
                    Console.WriteLine(Thread.CurrentThread.Name);
                    Console.WriteLine("Done");
                    for (int i = 0; i < 10000; i++) { 
                    }
                    done = true;
                }
            }
​
        }
2.ThreadPool线程池
           
  //一个参数  WaitCallback 委托类型
            //标准写法
            //ThreadPool 使用线程池 操作线程
            WaitCallback waitCallback = new WaitCallback(ProgramMothod);
            //在分线程中执行方法  
            ThreadPool.QueueUserWorkItem(waitCallback);
​
            //简写1
            WaitCallback waitCallback1 = arg => Console.WriteLine("dosomething1");
            ThreadPool.QueueUserWorkItem(waitCallback1);
            //简写2
            ThreadPool.QueueUserWorkItem(e => {
                
                Console.WriteLine("dosomething2");
            });
     
             // 方式二:
            //QueueUserWorkItem 接收两个参数,
            //第一个参数是WaitCallback 委托类型,
            //第二个参数是object对象,用于传递给委托函数的参数
            ThreadPool.QueueUserWorkItem(e =>
            { 
                 Thread.Sleep(2000);//线程休眠
                People p = e as People;
                Console.WriteLine(p.Age);
            }, new People() { Age = 10 });
1)ThreadPool 如何阻塞主线程
          
  ManualResetEvent mreset = new ManualResetEvent(false);
            ThreadPool.QueueUserWorkItem(e =>
            {
                Thread.Sleep(2000);
                Console.WriteLine("dosomething3");
                mreset.Set();//开启主线程的mreset.waitOOne()
            });
            //阻塞主线程 等待分线程完成后 执行mreset.Set()后执行后续代码
            mreset.WaitOne();
            Console.WriteLine("阻塞主线程");
3、Task

Thread每次都会创建新线程,线程的创建和销毁是一个开销比较大的操作,Task每次执行将不会立即创建一个新线程,而是到CLR线程池查看是 否有空闲的线程,有的话就取一个线程处理这个请求,处理完请求后再把线程放回线程池,这个线程也不会立即撤销,而是设置为空闲状态,可供线程池再次调度, 从而减少开销。

开启Task分线程的三种方式
   //第一种
   var task1 = new Task(() =>
    {
       //TODO you code
    });
   task1.Start();//必须手动开启Start
    //第二种
    //第二种创建方式,工厂创建,直接执行  且绑定的都是无参无返回值的委托对象
   var task2 = Task.Factory.StartNew(() =>
    {
     
    });
    //第三种
    Task.Run(() =>{
 
    });
 //有返回值的写法
 Task<int> task = Task.Run(() => {
  return h(22); 
} );
Task的任务控制

Task比threadPool优点就是任务控制,很好的控制task的执行顺序,让多个task有序的执行

Task.Wait task1.Wait();就是等待任务执行(task1)完成,task1的状态变为Completed。 Task.WaitAll 待所有的任务都执行完成: Task.WaitAny 等待任何一个任务完成就继续向下执行 Task.ContinueWith 第一个Task完成后自动启动下一个Task,实现Task的延续 CancellationTokenSource 通过cancellation的tokens来取消一个Task。

      //如果线程中的结果 需要再后续使用 使用线程延续
      //线程延续
      Task<int> task4 = new Task<int>(() => {
                return 1111;
            });     
            task4.Start();
            task4.ContinueWith(tas =>
            {
                Console.WriteLine("task finished!");
                //获取task4 完成后的返回值结果
                Console.WriteLine(tas.Result); 
               
            });
       //例子2:一个Task完成后自动启动下一个Task,使用Task的延续
       static void Main(string[] args)
        {
 
            Task task = Task.Run(() => {    
                
                Thread.Sleep(3000);
                Console.WriteLine("1");
 
            });
       
            var result = task.ContinueWith<string>(tas =>
            {
                Console.WriteLine("task finished!");
                Task task1 = Task.Run(() =>
                {
                    Thread.Sleep(3000);
                    Console.WriteLine("2");
                });
              
                return "This is task result!";
            });

Task线程取消方法
            //1.初始化线程取消类
            var tokenSource = new CancellationTokenSource();
            //2.获取线程取消标记
            var token = tokenSource.Token;
            //3.开启task线程  并且绑定取消线程标记
            var task = Task.Run(() =>
            {
                for (var i = 0; i < 1000; i++)
                {
                    Thread.Sleep(1000);
                    //是否执行取消方法 如果取消  为true  反之为 false
                    if (token.IsCancellationRequested)
                    {
                        Console.WriteLine("Abort mission success!");
                        return;
                    }
                }
            }, token);
            //取消线程后回调方法
            token.Register(() =>
            {
                Console.WriteLine("Canceled");
            });
            Console.WriteLine("Press enter to cancel task...");
            Console.ReadKey();
            //取消线程方法
            tokenSource.Cancel();
            Console.ReadKey();
4、同步异步

异步:表示执行某项操作之后不等待操作结束,但可以在操作结束后收到通知

同步:

1.net5.0推出了async/await async/await特性是与Task紧密相关的

2.async 是“异步”的简写,sync 是“同步”的简写

await 是 async wait 的简写。await 用于等待一个异步方法执行完成

       //如何通过使用async/await  完成异步编程\
        //1. async 必须修饰方法  被修饰的方法 表示是一个异步方法
​
        //2.async 和await必须连用  如果不使用await 那么这个方法还是同步方法
        //3.async 描述的方法 的返回值类型必须是void 或者是task 或者task<T>
        //4.await 描述的也是方法 但是必须是使用线程(task)的方法
        //5.Async方法在执行的时候,开始是以同步的方式执行,直到遇到await关键字,
        //从await关键字开始,C#会另起一个线程执行await后面的代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值