一、多线程概念
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();
}
}