多线程学习笔记第二篇
前言:这篇博客主要是在上一篇博客的基础上,重新复习了一下上一篇博客的内容,讲解了一些特殊的使用,并且使用了大量的案例来说明,主要说明了异步委托的使用和回调函数执行异步委托以及跨线程访问控件的解决方案和一个双色球的案例。这篇文章我以代码的形式写了,里面有大量的注释,我们可以详细的研究,很高兴能和你们一起研究。
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代码结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | 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如果您认为这篇文章还不错或者有所收获,您可以通过右边的“打赏”功能 打赏一杯咖啡,本页版权归作者和博客园所有,欢迎转载,但未经作者同意必须保留此段声明, 且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构