多线程学习笔记第二篇
前言:这篇博客主要是在上一篇博客的基础上,重新复习了一下上一篇博客的内容,讲解了一些特殊的使用,并且使用了大量的案例来说明,主要说明了异步委托的使用和回调函数执行异步委托以及跨线程访问控件的解决方案和一个双色球的案例。这篇文章我以代码的形式写了,里面有大量的注释,我们可以详细的研究,很高兴能和你们一起研究。
1.线程的复习
(1) 多线程Thread调用委托方法的实现Demo
class Program
{
static void Main(string[] args)
{
Thread thread = new Thread(new ThreadStart(DemoMethod));
//设置线程参数
thread.IsBackground = true; //后台线程,常用的都是后台线程
//设置线程的名字
thread.Name = "给开发人员用的";
//设置线程的优先级(只是提议)
thread.Priority = ThreadPriority.Highest; //0-31
//启动线程,只是告诉操作系统线程准备好,开始执行此线程,但是并不一定线程立即执行
thread.Start();
Thread.Sleep(3000);
Console.ReadKey();
}
private static void DemoMethod()
{
Console.WriteLine("执行的工作线程是:{0}", Thread.CurrentThread.ManagedThreadId); ;
}
}
执行结果是:执行的工作线程是:10
(2)线程配合Lambda表达式的使用
static void Main(string[] args)
{
//第一种写法
Thread thread = new Thread(new ThreadStart(() =>
{
Console.WriteLine("执行的工作线程是:{0}", Thread.CurrentThread.ManagedThreadId); ;
}));
//第二种写法
new Thread(() =>
{
Console.WriteLine("执行的工作线程是:{0}", Thread.CurrentThread.ManagedThreadId); ;
}).Start();
//设置线程参数
thread.IsBackground = true; //后台线程,常用的都是后台线程
//设置线程的名字
thread.Name = "给开发人员用的";
//设置线程的优先级(只是提议)
thread.Priority = ThreadPriority.Highest; //0-31
//启动线程,只是告诉操作系统线程准备好,开始执行此线程,但是并不一定线程立即执行
thread.Start();
Thread.Sleep(3000);
Console.ReadKey();
}
//执行结果是:
//执行的工作线程是:4
//执行的工作线程是:3
(3)带参数的线程执行
static void Main(string[] args)
{
//定义带参数的线程
Thread thread = new Thread(new ParameterizedThreadStart(ParameterMethodDemo));
//开启线程,传递参数
thread.Start("韩迎龙");
Thread.Sleep(3000);
}
private static void ParameterMethodDemo(object obj)
{
Console.WriteLine("执行一个带参数的线程方法:{0}", obj);
}
//执行结果:执行一个带参数的线程方法:韩迎龙
(4)异步委托回调函数的使用
namespace ReviewThread
{
//定义委托
internal delegate int AddDel(int a,int b);
class Program
{
static void Main(string[] args)
{
//定义委托变量的时候,如果是指向第一个方法,那么必须使用new关键字
AddDel del = new AddDel(Demo);
//同步调用
//int res = del(5, 3);
//异步调用,本质就是重新开启一个线程帮我们,执行委托的方法
//内部:开启一个新的线程执行委托
IAsyncResult result = del.BeginInvoke(2, 5, null, null);
//执行主线程要干的事情
//异步委托的好处是:不阻塞主线程
int methodRes = del.EndInvoke(result);
Console.WriteLine(methodRes);
Console.ReadKey();
}
public static int Demo(int a, int b)
{
return a + b;
}
//执行结果:7
}
}
2. 委托的异步调用:由另一个线程执行委托的方法
(1) 简单的异步委托调用Demo
namespace AsyncDelegate
{
internal delegate int AddDemoDel(int a,int b);
class Program
{
static void Main(string[] args)
{
Console.WriteLine("当前主线程是:{0}", Thread.CurrentThread.ManagedThreadId);
AddDemoDel addDemoDel = new AddDemoDel(AddDemo);
//委托的异步调用
//开始调用委托方法,自动创建一个线程并执行委托的方法
IAsyncResult result = addDemoDel.BeginInvoke(4, 5, null, null);
//得到委托的返回值
int inta = addDemoDel.EndInvoke(result); //阻塞当前主线程,只等到子线程执行完成,并返回方法的返回值之后继续执行
Console.WriteLine("主线程执行完毕,结果是" + inta);
Thread.Sleep(10000);
Console.ReadKey();
}
private static int AddDemo(int a, int b)
{
Thread.Sleep(3000);
Console.WriteLine("当前执行的线程是:{0}", Thread.CurrentThread.ManagedThreadId);
return a + b;
}
//执行结果:
//当前主线程是:9
//当前执行的线程是:10
//主线程执行完毕,结果是9
}
}
(2)设置一个回调函数执行异步委托
namespace AsyncDelegate
{
internal delegate int AddDemoDel(int a,int b);
class Program
{
static void Main(string[] args)
{
Console.WriteLine("当前主线程是:{0}", Thread.CurrentThread.ManagedThreadId);
AddDemoDel addDemoDel = new AddDemoDel(AddDemo);
//指定回调函数,处理的异步委托
addDemoDel.BeginInvoke(3, 4, new AsyncCallback(DelCallBackFuncDemo), "韩迎龙");
Console.WriteLine("主线程执行完毕");
Console.ReadKey();
}
//定义一个委托单额回调方法
public static void DelCallBackFuncDemo(IAsyncResult arr)
{
Console.WriteLine("回调函数执行的线程是:{0}", Thread.CurrentThread.ManagedThreadId);
//当我们的委托方法执行完成后,会自动调用次回调函数
AsyncResult result=(AsyncResult)arr;
Console.WriteLine("在回调方法里面获取到的传递过来的状态:{0}",result.AsyncState);
//回调函数获取当前委托方法执行的结果
AddDemoDel del = (AddDemoDel)result.AsyncDelegate; //将异步委托转成我们自定义的委托类型
int funResult = del.EndInvoke(result); //获取方法的返回值
Console.WriteLine("获取到当前方法执行的结果是:{0}", funResult);
}
private static int AddDemo(int a, int b)
{
Thread.Sleep(3000);
Console.WriteLine("当前执行的线程是:{0}", Thread.CurrentThread.ManagedThreadId);
return a + b;
}
}
}
//执行结果如图所示:
3. 一个双色球变化的案例
(1) 创建一个Windows窗体应用程序(Winform),起名为DoubleBallDemo,拖放一个Button控件
(2)项目Demo代码结果如下:
namespace DoubleBallDemo { //定义设置标签值的委托类型 public delegate void SetLbTextDel(string str,Label label); public partial class Form1 : Form { List<Label> listlabel = new List<Label>(); public bool ISStop = true; //是否结束,改变Label的值 public Form1() { InitializeComponent(); //设置当前的按钮的名字为开始 btnStartEnd.Text = "开始"; //初始化6个Label标签 for (int i = 0; i < 6; i++) { Label lblDemo = new Label(); lblDemo.Text = "0"; lblDemo.AutoSize = true; //自动调整大小 lblDemo.Location = new Point(10 + i * 50, 50);//在X轴上每隔50放一个控件 //第一将当前控件放到窗体里面去 Controls.Add(lblDemo); //往当前集合变量里面添加当前标签 listlabel.Add(lblDemo); } } private void btnStartEnd_Click(object sender, EventArgs e) { //现在点击的是开始按钮 if (btnStartEnd.Text.Equals("开始")) { this.ISStop = false; //启动一个线程,帮我们改变标签的数字 Thread thread = new Thread(() => { Random rand = new Random(); while (!ISStop) { for (int i = 0; i < listlabel.Count; i++) { //listlabel[i].Text = rand.Next(0, 9).ToString(); //使用Invoke方法 //Invoke方法内部会沿着控件创建的路径往上找到创建此控件的线程,找到线程之后会直接使用此线程调用委托方法 //谁创建的此标签,那么就由谁调用后面传过来的委托 //标志:标志当前的控件是否是当前线程创建的 if (listlabel[i].InvokeRequired) { listlabel[i].Invoke(new SetLbTextDel(SetLbText), rand.Next(0, 9).ToString(), listlabel[i]); } else { //如果当前控件直接就是当前线程创建的那么就可以直接访问就行了 SetLbText(rand.Next(0, 9).ToString(), listlabel[i]); } } Thread.Sleep(200); } //线程的方法执行完成后,会自动退出线程,线程的资源会自动释放 }); thread.IsBackground = true; thread.Start(); //把当前按钮的名字改成结束 btnStartEnd.Text = "结束"; } else { //停止线程,改变Laebl的数据 //尽量避免直接关闭一个线程:abort方法 //关闭线程,一般使用标志。 this.ISStop = true; //把当前的按钮改成开始 btnStartEnd.Text = "开始"; } } private static void SetLbText(string str, Label label) { label.Text = str; } } }
(2) 项目显示截图:
初心商城:初心商城
作者:韩迎龙(Kencery) MVC/.NET群:159227188如果您认为这篇文章还不错或者有所收获,您可以通过右边的“打赏”功能 打赏一杯咖啡,本页版权归作者和博客园所有,欢迎转载,但未经作者同意必须保留此段声明, 且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利