C#之多线程(上)

一、多线程概念

1)进程:

简单说是指在系统中正在运行的一个应用单元。通过资源管理器我们可以看到对进程的描述

2)线程:

线程是系统分配处理器时间资源的基本单元

3)多线程技术适用环境:

任务执行比较耗时的情况,也同时可以解决一些非常耗时的程序长时间占用CPU资源

4)多线程的特点:

运行顺序不确定

线程之间平行执行

5)定义一个线程:

一般方式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;							//多线程命名空间
//线程一般定义方式
class Demo{
    public void ThreadMethod1(){
        for(int i=0;i<100;i++){
            Console.WriteLine("线程1");
        }
    }
    public void ThreadMethod2(){
        for(int i=0;i<100;i++){
            Console.WriteLine("线程2");
        }
    }
    public void Test(){
    Thread t1=new Thread(ThreadMethod1);
    t1.Start();
    Thread t2=new Thread(ThreadMethod2);
    t2.Start();
}
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test();
    }
}

Lamda表达式方式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;//多线程命名空间
class Demo{
    public void Test(){
        Thread t1=new Thread(
            ()=>for(int i=0;i<100;i++)
            	{
       				Console.WriteLine("Lamba 线程1");
    			}
        );
    	t1.Start();
        Thread t2=new Thread(
            ()=>for(int i=0;i<100;i++)
            	{
       				Console.WriteLine("Lamba 线程2");
    			}
        );
    	t2.Start();
    }
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test();
    }
}

二、线程传参与返回值

1)线程的参数传递

第一:使用带object参数的方法,具体使用start()传递参数

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;//多线程命名空间
class Demo{
    public void DownLoadFile(object fileName){
        Console.WriteLine("文件名:"+fileName.ToString)
        Console.WriteLine("下载文件:"+Thread.CurrentThread.ManagedThreadId);//线程的ID号
        Thread.Sleep(1000);//线程休眠1秒钟
        Console.WriteLine("下载完毕");
    }
	//学习简单的线程传递参数
    public void Test(){
        Thread t=new Thread(DownLoadFile);
        t.Start("abc.mov");//带参线程
    }
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test();
    }
}

第二:可以定义专门的类,在New对象的时候,在构造函数中加载参数,从而实现线程中带参数运行。

//线程使用的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;//多线程命名空间
public class MyThread{
    private string _FilePath;
    private string _FileName;
    public MyThread(string path,string fileName){
        _FilePath=path;
        _FileName=fileName;
    }
    public void DownFileDownload(){
        Console.WriteLine("开始下载:"+_FilePath+"/"+_FileName);
        Thread.Sleep(2F);
        Console.WriteLine("下载完毕");
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;//多线程命名空间
class Demo{
    //线程传递多个参数
    public void Test(){
            
        }
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test();
    }
}

 使用委托开启一个线程,参数传递,以及获取线程的返回数值

注意:“后台线程”会随着“前台线程”的关闭而自动关闭。

//无参委托传值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;//多线程命名空间
class Demo{
    public void ThreadMethod1(){
        Console.WriteLine("线程3");
    }
    public void test(){
        Action ac=ThreadMethod1;//委托开启的线程为“后台线程”
        ac.BeginInvoke(null,null);//BeginInvoke 开启异步调用
        Console.ReadLine();//不加ReadLine,主线程即前台线程会直接快速运行而自动结束,后台线程也会关闭不运行
    }
    static void Main(string[] args){
        
        Demo obj=new Demo();
        obj.Test();
    }
}
//带参委托传值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;//多线程命名空间
class Demo{
    public void ThreadMethod(int num){
        Console.WriteLine("线程4,参数="+num);
    }
    public void Test(){
        Action<int> ac=ThreadMethod;
        ac.BeginInvoke(88),null,null;
        Console.ReadLine();
    }
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;//多线程命名空间
class Demo{
    public int DownLoadMoreFile(int num){
        Console.WriteLine("下载很多文件");
        Thread.Sleep(3000);//持续3秒
        return num+2000;
    }
    //委托开启线程,传参,且接受线程的返回数值,使用“状态结果”
    public void Test1(){
        //后台线程
        Func<int,int> fn=DownLoadMoreFile;
        //IAsyncResult表示异步调用的状态,异步可以使两个线程不同时调用
        IAsyncResult result= fn.BeginInvoke(100,null,null);
        //IsComleted查询result的状态是否完成,如果没有完成则。。。
        //前台线程等待前台线程的完成
        while(result.IsComleted){
            Console.WriteLine(".");
            Thread.Sleep(10);
        }
        //取得结果
        int inrResult=fn.EndInvoke(result); 	//EndInvoke表示异步调用结束
        Console.Write("线程返回的数值="+intResult);
    }
    //委托开启线程,传参,且接受线程的返回数值,使用“等待句柄”。
     public void Test2(){
        //后台线程
        Func<int,int> fn=DownLoadMoreFile;
        //IAsyncResult表示异步调用的状态,异步可以使两个线程不同时调用
        IAsyncResult result= fn.BeginInvoke(100,null,null);
        //等待5秒,等待句柄
        boole boResult=result.AsyncWaitHandle.WaitOne(5000);
        //如果返回为真,则结束
        if(boResult){
            //取得结果
        	int inrResult=fn.EndInvoke(result); 	//EndInvoke表示异步调用结束
            Console.Write("用“等待句柄”,线程返回的数值="+intResult);
        }else{
            Console.WriteLine("规定时间内线程没有取得子线程的结果");
        }
    }
    //委托开启线程,传参,且接受线程的返回数值,使用“回调函数”。
    public void Test3(){
        Console.WriteLine("使用'回调函数'方式");
        //后台线程,Func委托调用
        Func<int,int> fn=DownLoadMoreFile;
        //fn的状态,操作的参数,OnCallBach是回调函数,当子线程结束的时候,自动调用
        //回调函数的参数,回调函数启动子线程,主线程继续工作,不需要等
        fn.BeginInvoke(200,OnCallBack,fn);
        //........还可以写很多的方法运行
        Console.ReadLine();
    }
    //回调函数的方法,参数为异步调用的结果状态
    void OnCallBack(IAsynacResult ar){
        //异步的状态转换为定义的Func委托的类型,用Func委托接收
        Func<int,int> res=ar.AsyncState as Func<int,int>;
        //定义委托的结果返回一个Int类型
        int IntResult=res.EndInvoke(ar);
        Console.WriteLine("在回调函数中取得结果="+intResult);
    }
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test1();
        obj.Test2();
        obj.Test3();
    }
}

三、线程的优先级与状态

1)线程的优先级可以影响线程的调用顺序,我们可以通过使用Priority枚举属性来设置线程的优先级

说明:

Highest 最高级别优先

AboveNormal 在Heighest级别后,Normal之前

Normal 默认情况下初始为Normal

BelowNormal 在Normal之后,在lowest之前

Lowest 在BelowNormal之后,最低

2)线程(Thread)的状态控制

Start() 开始

Abort()终止

Sleep()休眠 过了多长时间 继续执行

Join() 阻塞 过了多长时间 某个线程执行完毕 再执行

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;//多线程命名空间
class Demo{
    public void ThreadMethod1(){
        for(int i =0;i<100;i++;){
            Console.WriteLine("线程1");
        }
    }
    public void ThreadMethod2(){
        for(int i =0;i<100;i++;){
            Console.WriteLine("线程2");
        }
    }
    public void ThreadMethod3(){
        for(int i =0;i<100;i++;){
            Console.WriteLine("线程3");
        }
    }
    //演示线程的优先级
    public void Test1(){
        Console.WriteLine("学习线程的优先级");
        Thread t1=new Thread(ThreadMethod1);
        Thread t2=new Thread(ThreadMethod2);
        Thread t3=new Thread(ThreadMethod3);
        t1.Start();
        t2.Start();
        t3.Start();
        
        //线程的优先级控制
        t3.Priority=ThreadPriority.Highest;
        t2.Priority=ThreadPriority.Normal;
        t1.Priority=ThreadPriority.Lowest;
    }
    
    //线程的状态控制
    public void Test2(){
        Thread t1=new Thread(ThreadMethod1);
        t1.Start();			//开始
        t1.Abort();			//结束
        t1.Join(1000);		//阻塞
        
        Thread.Sleep(1000);	//休眠
    }
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test1();
        obj.Test2();
    }
}

四、前台线程与后台线程

1)应用程序分为”前台线程“与”后台线程“

应用程序的主线程以及使用Thread构造的线程都默认为前台线程,线程池中的线程是后台线程。(我们默认创建的线程就是”前台线程“)

只有所有的前台线程都关闭后,系统才能真正的关闭。后台线程,会随着所有前台线程关闭而自动关闭

后台线程不会阻止进程的终止。属于某个进程的所有前台线程都终止后,该线程就会被终止,所有剩余的后台线程都会停止且不会完成

可以在任何时候将前台线程修改为后台线程,方式是设置Thread.IsBackground属性

通过BeginXXX方法运行的线程都是后台线程

2)”前台线程“与”后台线程“的适用场合

”前台线程“:重要核心的,或者需要长时间等待的任务(例如UI界面线程、发送数据的线程)

”后台线程“:非常适合于完成后台任务,非核心且用于处理时间较短的任务适用。(例如监听客户端的请求、Word拼写检查)

//学习前台线程与后台线程
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;//多线程命名空间
class Demo{
    public void DownLoadFile(object fileName){
        Console.WriteLine("文件名:"+fileName.ToString())
        Console.WriteLine("下载文件:"+Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(3000);//持续3秒
        Console.WriteLine("下载完毕");
    }
    //学习后台线程
    public void Test(){
        Thread t1=new Thread(DownLoadFile);
        t1.Start("abc.mov");
        //把当前线程改为后台线程
        t1.IsBackground=true;
        //在前台线程直接结束的时候,后台线程会直接结束不显示,所以需要用ReadLine让主线程一直等待。
        Console.ReadLine();
    }
    static void Main(string[] args){
        Demo obj=new Demo();
        obj.Test();
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_49251429/article/details/123723401