ThreadPool线程池
线程池他是利用一种池子技术,池子他是一个容器用来保存线程,在程序使用的时候会从线程池中构建一个线程完成指定的任务。
当任务完成后,该线程并不会消亡关闭,而是被挂起等待下一个任务的到到来激活该线程执行任务
当线程池中线程全部用完之后,会继续实例化一个新线程来执行分配的任务,线程池中的线程可以被反复使用。
QueueUserWorkltem():他是一个重载的方法
当接收一个参数的时候,只接收一个委托方法
当接收两个参数的时候,第一个参数是委托方法,第二个参数是传入的参数值
namespace 线程池__ { internal class Program { static void Main(string[] args) { //ThreadPool //- 当接收一个参数的时候,只接收一个委托方法 //- 当接收两个参数的时候,第一个参数是委托方法,第二个参数是传入的参数值 //ThreadPool.QueueUserWorkItem(Print, 100); //Thread.Sleep(1000); //线程同步类 信号类 ManualResetEvent mre = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(e => { for (int i = 0; i <=(int)e; i++) { Console.WriteLine(i); } //当线程池中该线程任务执行完毕后给当前程序所有线程开启信号,其他线程收到信号后,会恢复执行 mre.Set(); },1000); //让主线程(其他线程)处于等待状态 mre.WaitOne();//当该线程收到信号时,被唤醒处于就绪状态(随时执行) Console.WriteLine ("22222222"); //如果主线程(其他线程)执行任务完毕后,让主线程(其他线程)进入等待状态,进入到无信号状态 mre.Reset(); } //打印数字 //public static void Print(object obj) //{ // for (int i = 0; i < 10; i++) // { // Console.WriteLine(i); // } //} } }
委托
delegate---委托
在C#中,委托是一种引用类型,类似于抽象方法(但是方法名称不一致,方法声明的格式保持一致),表示的是对特定参数列表和返回类型方法的引用
委托一般适合于实现事件和回调方法,所有的委托都来自于System.Delegate类中
在实例化委托的时候,可以将委托的实例与具有相同返回值类型的方法进行关联,这样我们就可以通过委托来回调方法。
委托还可以将方法作为参数传递给其他方法-->高阶函数
委托的特点
-
委托允许将方法作为参数传递
-
委托可以用于回调方法
-
方法不必与委托类型完全一致
-
C#当中引入了匿名函数,可以将代码块作为参数进行传递,同时又引入了Lambda表达式,可以简化匿名函数的编写,使编写的内联代码更加精简,可以把匿名函数和Lambda表达式都可以被编写成委托类型
声明委托
语法格式:
public delegate 返回值类型 委托名称(参数列表);//参数列表定义时,可以空参也可以多参 //定义一个委托 public delegate void WaitCallBack(object state);
实例化委托
委托一旦声明后,想要使用他,就必须使用new关键字来创建委托对象,同时想要将其与特定的方法进行关联
示例
namespace 委托1 { internal class Program { // 委托定义 public delegate void MyDelegate(string str); static void Main(string[] args) { // 实例化委托 MyDelegate myDelegate = new MyDelegate(PrintString);//此处不是传递字符串而是和委托声明格式一样的方法 // 调用委托 myDelegate("Hello World!"); Console.ReadKey(); } // 委托方法定义 public static void PrintString(string str) { Console.WriteLine(str); } } }
namespace 委托1 { internal class Program { //委托 public delegate int Number(int n);//创建委托 public static int num = 10; public static int AddNumber(int n)//委托的方法 { num += n; return num; } static void Main(string[] args) { Number number = new Number(AddNumber);//实例化委托 number(5);//相加的数 Console.WriteLine(num);//结果 } } }
委托的应用
namespace 委托的应用 { internal class Program { //定义一个和委托格式一样的方法 public static bool IsEven(int num) { return num % 2 == 0; } public static void Print(int num) { Console.WriteLine(num + " "); } static void Main(string[] args) { //定义一个整数数组 int[] number = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 26, 78 }; // 取出nums数组中所有的偶数放到一个数组里 //Array是类 int[] evenNumbers = Array.FindAll(number, IsEven); Array.ForEach(evenNumbers, Console.WriteLine); Array.ForEach(number, Print); //例子2 string[] str = { "hello", "world", "c#", "is", "awesome" }; //把string数组中字母都换成大写 string[] upperStr = Array.ConvertAll(str, ToUpper); Array.ForEach(upperStr, Console.WriteLine); //把string数组中字母都换成小写 string[] lowerStr = Array.ConvertAll(str, ToLower); Array.ForEach(lowerStr, Console.WriteLine); //数组每个字符串前后加上* string[] starStr = Array.ConvertAll(str, AddStar); Array.ForEach(starStr, Console.WriteLine); } //例子2 //定义一个委托 public delegate string HandString(string str);// //定义一个方法,参数为委托类型,返回值为委托方法的返回值类型 public static string HandStrin(HandString handString, string str) {for (int i = 0; i < str.Length; i++) { str = handString(str); } return str; } //转换成大写 public static string ToUpper(string str) { return str.ToUpper(); } //转换成小写 public static string ToLower(string str) { return str.ToLower(); } //把字符串前后加上* public static string AddStar(string str) { return "*" + str + "*"; } } }
总结:
委托的实际应用场景:委托就是帮助我们在高阶函数当中回调方法。
在高阶函数当中,定义一个委托类型的 参数
在调用高阶函数时,传入与委托类型相匹配的方法签名,或者是直接传入一个与委托相匹配的Lambda表达式。
多播委托
多播委托也称之为合并委托或者组播。
委托对象可以通过+号和—号运算符将多个对象分配给一个委托,或者是从委托当中移除指定的对象
委托的这个属性我们称之为委托多播,又称之为组播
利用这个属性可以在调用委托的时候在委托上绑定一个方法列表实现批量调用
备注:
这些方法列表的声明格式和委托相一致,才能实现多播
namespace 多播委托 { internal class Program { //定义一个委托 public delegate int ChangNum(int num); //定义变量 public static int num = 10; //定义一个方法 public static int AddNum(int n) { num +=n; return num; } public static int SubNum(int n) { num -= n; return num; } public static int MulNum(int n) { num *= n; return num; } public static int DivNum(int n) { num /= n; return num; } static void Main(string[] args) { //创建委托对象 // ChangNum changeNum = new ChangNum(AddNum); //简化版 ChangNum changeNum = AddNum; //实现多播委托 changeNum += SubNum; changeNum += MulNum; changeNum += DivNum; //调用委托 Console.WriteLine(changeNum(5)); Console.WriteLine(num); //减播 changeNum -= SubNum; Console.WriteLine(changeNum(3)); Console.WriteLine(num); } } }
泛型委托
通用性,委托定义时里面是有泛型的
namespace 泛型委托 { internal class Program { static void Main(string[] args) { int[] arr = { 1, 2, 3, 4, 5 }; int[] newArr = Array.FindAll(arr, e => e % 2 == 0); //找出数组最大值 //int max = Array.Find(arr, e => e == arr.Max()); int maxInt=FindMax(arr, (int a, int b) => a > b); Console.WriteLine (maxInt); string[] arr2 = { "hello", "world", "c#", "is", "awesome" }; //找出数组中长度最长的元素 //string longestStr = Array.Find(arr2, e => e.Length == arr2.Max(s => s.Length)); string longestStr = FindMax(arr2, (string a, string b) => a.Length > b.Length); Console.WriteLine(longestStr); } //定义一个委托 public delegate bool Delcompare<T>(T o1, T o2); //定义一个方法,该方法参数中有泛型委托 public static T FindMax<T>(T[] arr, Delcompare<T> compare) { T max = arr[0]; for (int i = 1; i < arr.Length; i++) { if (compare(arr[i], max)) { max = arr[i]; } } return max; } } }
GDI
GDI : Graphic Device Interface绘图装置接口,它主要是用于绘制图形,可以将应用程序和绘图硬件进行分割隔离。
主要在窗体当中进行绘制(Form),当窗体移动到屏幕外围,再移动到屏幕里面会触发窗体重绘事件,窗体中原来构建的控件会消失,如果想要中窗体移动过程中保持窗体的控件不变,想要在Form窗体中绑定Paint事件,对窗体中原有的控件重新绘制
Paint事件
//画图示例 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { //先创建Graphics对象 Graphics g = this.CreateGraphics(); //创建Pen对象 Pen pen = new Pen(Color.Red, 5); //画线 g.DrawLine(pen, 10, 10, 100, 100); //释放Graphics对象 g.Dispose(); } private void Form1_Load(object sender, EventArgs e) { // } private void Form1_Paint(object sender, PaintEventArgs e) {//绑定重绘 button1_Click(sender, e); } private void button2_Click(object sender, EventArgs e) { //画一个圆 Graphics g = this.CreateGraphics(); Pen pen = new Pen(Color.Red, 5); g.DrawEllipse(pen, 10, 10, 100, 100); g.Dispose(); //画一个实心圆 g = this.CreateGraphics(); pen = new Pen(Color.Blue, 5); g.DrawEllipse(pen, 150, 10, 100, 100); g.Dispose(); } }
总结
线程池
-
核心:通过容器管理线程,线程可重复利用(任务完成后不消亡,等待新任务),避免频繁创建销毁线程的开销。
-
关键方法:
QueueUserWorkItem
,重载形式:单参数(仅委托)、双参数(委托 + 参数)。 -
线程同步:可通过
ManualResetEvent
控制线程状态(Set()
唤醒、WaitOne()
等待、Reset()
重置为等待状态)。
委托
-
本质:引用类型,指向具有特定参数列表和返回值的方法,用于事件、回调及将方法作为参数传递(高阶函数)。
-
声明与使用:
public delegate 返回值 委托名(参数)
,实例化时关联匹配方法,支持匿名函数或 Lambda 简化编写。 -
应用:在高阶函数中回调方法(如
Array.FindAll
用委托筛选数组,Array.ForEach
用委托处理元素)。
多播委托
-
特性:通过
+
合并多个方法、-
移除方法,形成方法列表,调用时批量执行(要求方法与委托格式一致)。
泛型委托
-
特点:带泛型的委托,增强通用性,可适配不同类型的方法(如示例中
FindMax
方法用泛型委托比较不同类型数组的最大值)。
GDI
-
作用:图形设备接口,用于窗体绘图,隔离应用程序与绘图硬件。
-
关键:需绑定
Paint
事件以在窗体重绘时保留图形;核心对象为Graphics
(绘图上下文)和Pen
(画笔),可绘制线、椭圆等,注意资源释放(Dispose()
)。