C#基础——线程(线程池、线程锁、线程抢占、多线程)
线程
进程(Process)是由操作系统分配资源并执行的一个独立的程序实,属于Windows的概念,进程结束就表示程序关闭了。
线程(Thread)是程序中执行的最小单位。一个线程代表了一个独立的执行流,可以独立运行,执行特定的任务。每个应用程序至少有一个线程,即主线程,用于执行主要的程序代码。
进程可以包含多个线程,但是主线程只有一个,如果遇到繁琐的任务,可以开辟线程,开辟出来的线程叫做分线程
static void Main(string[] args) { //Main是主函数Console.WriteLine("这句代码是在主线程中执行的");//设置主线程名称//Thread.CurrentThread 获取当前正在运行的线程Thread.CurrentThread.Name = "Main";Console.WriteLine(Thread.CurrentThread.Name); //Main
}
Thread 类 :表示一个操作系统级别的线程,允许你在应用程序中创建、控制和管理线程。
创建分线程的第一种方式
//创建线程的第一种方法设置线程委托
//1、设置线程委托(目的是为了告诉线程应该执行的耗时任务是谁)
ThreadStart childref = new ThreadStart(Promothod);
//2、把委托交给Thread
Thread childThread = new Thread(childref);
//3、可以分线程Thread分配一个名字,便于甄别
childThread.Name = "分线程1";
// Start 执行分线程
childThread.Start();//定义一个函数
public static void Promothod() {Console.WriteLine(Thread.CurrentThread.Name);
}
创建线程的第二种方式(箭头函数)
Thread thread2 = new Thread(() => {Console.WriteLine("这是分线程2");
});
thread2.Start();
Sleep 线程休眠
Thread thread3 = new Thread(() => {Console.WriteLine("这是分线程3,开始睡觉~耗时3秒");//Sleep 线程休眠的毫秒数Thread.Sleep(3000); Console.WriteLine("睡醒了,开始敲代码了。");
});
thread3.Start();//Abort 线程启动之后,使用完毕最好要销毁掉thread3.Abort();
带有参数的委托类(使用线程委托方法)
//带有参数的委托类,参数必须是object类型,否则会报错
ParameterizedThreadStart ptstart = new ParameterizedThreadStart(Promothod2);
Thread thread4 = new Thread(ptstart);
thread4.Start("我是传进来的参数");//定义一个参数是对象类型的函数
public static void Promothod2(object data) {Console.WriteLine("传进来的参数:" + data);
}
带有参数的委托类(使用箭头函数方法)
Thread thread5 = new Thread((e) => {Console.WriteLine(e);
});
thread5.Start(abc);
Join 阻塞线程
static void Main(string[] args) { //Main是主函数//创建一个线程并执行Thread thread6 = new Thread((e) => {Console.WriteLine(e);Thread.Sleep(6000)});thread6.Start(abc);// Join 阻塞当前依赖的主线程,直到分线程执行完毕thread6.Join();//下面这行代码需要等到上面的线程运行完才会执行Console.WriteLine("这句代码是在主线程中执行的");
}
线程抢占
线程抢占是由操作系统负责的,它决定哪个线程将获得 CPU 的执行时间。
如果两个线程同时对某一个资源进行访问,就可能出现线程抢占的问题。
线程锁
线程锁是一种用于控制多个线程对共享资源进行访问的机制,以防止并发访问时出现数据不一致或错误的情况。使用锁能够确保在某一时刻只有一个线程可以访问共享资源,其他线程需要等待获取锁的释放才能继续执行。
线程锁抢票案例、
static int p = 1;
static readonly object locker = new object(); //当做一个锁
static void Main(string[] args) {Thread thread1 = new Thread(Go);thread1.Name = "张三";thread1.Start();Thread thread2 = new Thread(Go);thread2.Name = "李四";thread2.Start();
}
static void Go() {
//lock 语句获取给定对象的互斥 lock,执行语句块,然后释放 lock。 持有 lock 时,持有 lock 的线程可以再次获取并释放 lock。 阻止任何其他线程获取 lock 并等待释放 lock。 lock 语句可确保在任何时候最多只有一个线程执行其主体。lock (locker) {Console.WriteLine(Thread.CurrentThread.Name + "进来了,此时票数为:" + p + "张。");if (p == 1) {Console.WriteLine(Thread.CurrentThread.Name + "买到了" + p + "张票。");} else {Console.WriteLine(Thread.CurrentThread.Name + "没抢到,继续加油!");}}p--;
}
Tack多线程
Task: 是用于表示可以异步执行的操作的类。它允许你在单独的线程或线程池中执行任务,而不必直接操作线程。
Task特点:
- 异步执行:
Task
允许你执行长时间运行的操作,而不会阻塞主线程,从而提高程序的响应性。 - 任务调度:
Task
可以由系统自动分配到线程池中的线程,也可以使用TaskScheduler
进行任务调度和控制。 - 任务链式调用:
Task
可以进行任务链式调用,允许一个任务完成后自动开始另一个任务,形成任务流水线。
创建一个简单的Task对象
var task1 = new Task(() => {Console.WriteLine("task分线程任务");
});
//实例化Task之后也需要调用Start才会执行
task1.Start();
创建一个带参数的Task对象
//携带参数,参数放在箭头函数的后面
Task task2 = new Task(e => {Console.WriteLine(e);
}, 123);
task2.Start();
Run 在线程池上运行的指定工作排队,并返回该工作的任务或Task
//带有返回类型,Run适合多线程的操作
//使用Run方法就不需要Start在开启了
Task task = Task.Run(() => {for (int i = 0; i < 10; i++) {Console.WriteLine("task:{0}", (i + 1));Thread.Sleep(500);}
});Task task2 = Task.Run(() => {//Wait 只有等到第一个执行完毕之后才会执行第二个task.Wait();Console.WriteLine("task2开始执行了。");
});//Task.WaitAll(task);//等待所有任务都执行完毕(大家一起执行)
//Task.WaitAny(task);//任意一个任务完成都会向下执行(竞速)//task3.ContinueWith(t => { }); //上一个task完成之后会自动启动下一个task,实现task的延续
Task task5 = Task.Run(() => {Console.WriteLine("5555");
});task5.ContinueWith(t => {Task.Run(() => {Console.WriteLine("test");});
});
线程池
线程池(ThreadPool):线程和线程池都是进行多线程操作的。线程池可以用来理解为是保存线程的一个容器。
//WaitCallback 是一个委托类型,它用于表示一个在线程池中执行的方法。WaitCallback waitCallback = new WaitCallback(ProgramMothod);//创建线程池:在程序创建线程来执行任务的时候,如果交给了线程池操作,那么线程即使执行完毕了也不会被销毁,而是被挂起了,等待下一个任务被激活。//当线程池里面的资源不够用的时候,会实例化一个新线程,来执行。默认线程池里面的线程是会反复利用的。//标准写法ThreadPool.QueueUserWorkItem(waitCallback);//简写1(箭头函数)
WaitCallback w2 = arg => Console.WriteLine("do something2");
ThreadPool.QueueUserWorkItem(w2);//简写2(箭头函数)
ThreadPool.QueueUserWorkItem(e => {Console.WriteLine("dosimething3");
});//传参的写法(参入一个对象作为参数)
//第一个参数表示委托,第二个参数是参数对象,用于给委托传递数据
ThreadPool.QueueUserWorkItem((e) => {People p = e as People; //这里使用了 as 关键字转义类型Console.WriteLine(p.Id);
}, new People() { Id = 100 });//定义一个类型为object类型的方法
public static void ProgramMothod(object a) {Console.WriteLine("do something");
}//定义一个类
public class People {public int Id;
}
线程阻塞:线程在某个操作或条件下停止执行,直到满足特定条件后再继续执行。
ManualResetEvent 多任务通信,用来控制多个线程之间的执行顺序以及时间
ManualResetEvent和线程池(ThreadPool)配合使用
ManualResetEvent mreset = new ManualResetEvent(false);
// ManualResetEvent和线程池(ThreadPool)配合使用
ThreadPool.QueueUserWorkItem(m => {Thread.Sleep(2000);Console.WriteLine("准备干一些工作");mreset.Set(); // Set 发送命令,如果有mreset.WaitOne方法在,那么收到Set命令之后,后续的代码才会执行
});
// WaitOne 阻塞线程
//上面执行完才会执行下面的
mreset.WaitOne();
Console.WriteLine("waitOne收到信号才会打印");
ManualResetEvent和Task配合使用
//下面将用于个打印奇数和偶数的案例演示和Task配合使用的情况
ManualResetEvent je = new ManualResetEvent(false);
Task task = new Task(e => {//打印所有的奇数Js(e);je.Set(); //发送命令
}, 10);ManualResetEvent oe = new ManualResetEvent(false);
Task task2 = new Task(e => {//打印所有的偶数Os(e);oe.Set();//发送命令
}, 10);
task.Start();
task2.Start();
oe.WaitOne();
je.WaitOne();Console.WriteLine("奇数和偶数都打印完毕了");//定义一个打印奇数的方法
public static void Js(object e) {int x = Convert.ToInt32(e);for (int i = 1; i <= x; i += 2) {Console.WriteLine("奇数:" + i);Thread.Sleep(500);}
}
//定义一个打印偶数的方法
public static void Os(object e) {int x = Convert.ToInt32(e);for (int i = 0; i <= x; i += 2) {Console.WriteLine("偶数:" + i);Thread.Sleep(500);}
}
ThreadPool、Thread、Task三者 都是用于多线程编程的类或机制
三者的区别
ThreadPool
更适合处理较小的异步操作,而不需要手动创建和管理线程。Thread
提供了对线程的直接控制,但需要手动管理线程的生命周期。Task
是一个高级抽象,结合async/await
更方便编写和管理异步代码,它可以利用线程池或后台线程来执行任务。
使用工厂模式创建Task
//工厂模式创建Task
var task3 = Task.Factory.StartNew(() => {Console.WriteLine("这是使用Factory工厂模式创建的线程1");
});
Task.Factory.StartNew(() => {Console.WriteLine("这是使用Factory工厂模式创建的线程2");
});//带有返回类型的Task
Task<int> task4 = Task.Factory.StartNew<int>(() => {Console.WriteLine("这是使用Factory工厂模式创建的线程3");return 100;
});
//使用 Result 方法获取返回的值
Console.WriteLine(task4.Result);//100//带有返回类型和参数:数字100是匿名函数的参数,return 200 表示匿名函数的返回值
Task.Factory.StartNew<int>(e => {Console.WriteLine("这是使用Factory工厂模式创建的线程4");return 200;
}, 100);
相关文章:
C#基础——线程(线程池、线程锁、线程抢占、多线程)
线程 进程(Process)是由操作系统分配资源并执行的一个独立的程序实,属于Windows的概念,进程结束就表示程序关闭了。 线程(Thread)是程序中执行的最小单位。一个线程代表了一个独立的执行流,可…...

C# WPF上位机开发(QT vs WPF)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 最近经常收到朋友们的私信,他们对C# WPF开发很感兴趣,但是呢,正当准备学习的时候,又有人告诉他们应…...

2-高可用-负载均衡、反向代理
负载均衡、反向代理 upstream server即上游服务器,指Nginx负载均衡到的处理业务的服务器,也可以称之为real server,即真实处理业务的服务器。 对于负载均衡我们要关心的几个方面如下: 上游服务器配置:使用upstream server配置上…...

STM32 使用ARM仿真器设置
STM32单片机程序下载到单片机芯片中有两种方式,①编译生成HEX,使用程序烧录软件刷到单片机芯片里。②使用ARM仿真器下载程序。使用ARM仿真器的优势是,在工程编译没问题直接在Keil软件里就可以将程序下载到单片机里,并且程序可以在…...

【Java】spring
一、spring spring是一个很大的生态圈,里面有很多技术。 其中最基础的是spring framework,主要的技术 是springboot以及springcloud。 1、spring framework spring framework是spring生态圈中最基础的项目,是其他项目的基础。 1.1、核心…...

C语言中关于操作符的理解
本篇文章只会列出大家在生活中经常使用的操作符 算术操作符 在算数操作符中常用的有,,-,*,/,% ,我们重点讲一讲 / (除) 和 % (模) " / "运算 #include <stdio.h>int main() {int a5/2;fl…...

Flutter本地化(国际化)之App名称
文章目录 Android国际化IOS国际化 Flutter开发的App,如果名称想要跟随着系统的语言自动改变,则必须同时配置Android和IOS原生。 Android国际化 打开android\app\src\main\res\values 创建strings.xml 在values上右键,选择New>Values Res…...
Redis哨兵源码分析
在Redis server启动过程中,实现了实例化和初始化 1、哨兵实例化过程,采用redis sentinel指令实例化还是redis server下的参数实例化--sentinel。 // 检查服务器是否以 Sentinel 模式启动 server.sentinel_mode checkForSentinelMode(argc,argv);/* Re…...
安装Neo4j
jdk1.8对应的neo4j的版本是3.5 自行下载3.5版本的zip文件 地址 解压添加环境变量 变量名:NEO4J_HOME 变量值:D:\neo4j-community-3.5.0 (你自己的地址) PATH添加: %NEO4J_HOME%\bin (如果是挨着的注意前后英…...

华为鸿蒙开发适合哪些人学习?
随着鸿蒙系统的崛起,越来越多的人开始关注鸿蒙开发,并希望成为鸿蒙开发者。然而,鸿蒙开发并不适合所有人,那么哪些人最适合学习鸿蒙开发呢?本文将为您总结鸿蒙开发适合的人群。 一、具备编程基础的人 学习鸿蒙开发需要…...

深信服技术认证“SCSA-S”划重点:命令执行漏洞
为帮助大家更加系统化地学习网络安全知识,以及更高效地通过深信服安全服务认证工程师考核,深信服特别推出“SCSA-S认证备考秘笈”共十期内容,“考试重点”内容框架,帮助大家快速get重点知识~ 划重点来啦 *点击图片放大展示 深信服…...

Flink系列之:Savepoints
Flink系列之:Savepoints 一、Savepoints二、分配算子ID三、Savepoint 状态四、算子五、触发Savepoint六、Savepoint 格式七、触发 Savepoint八、使用 YARN 触发 Savepoint九、使用 Savepoint 停止作业十、从 Savepoint 恢复十一、跳过无法映射的状态恢复十二、Resto…...

使用宝塔面板部署前端项目到服务器
目录 文章目录 前言 一、第一步:创建文件夹 二、第二步:部署前端项目 三、第三步:打开防火墙 文章目录 前言第一步:创建文件夹第二步:部署前端项目第三步:打开防火墙总结 前言 在此之前,我…...

Enge问题解决教程
目录 解决问题的一般步骤: 针对"Enge问题"的具体建议: 以下是一些普遍适用的解决问题的方法: 以下是一些更深入的Enge浏览器问题和解决办法: 浏览器性能问题: 浏览器插件与网站冲突: 浏览…...

使用yarn安装electron时手动选择版本
访问1Password或者其他可以提供随机字符的网站,获取随机密码运行安装命令 操作要点,必须触发Couldnt find any versions for "electron" that matches "*"才算成功 将复制的随机密码粘贴到后面 例如:yarn add --dev elec…...

AIGC:阿里开源大模型通义千问部署与实战
1 引言 通义千问-7B(Qwen-7B)是阿里云研发的通义千问大模型系列的70亿参数规模的模型。Qwen-7B是基于Transformer的大语言模型, 在超大规模的预训练数据上进行训练得到。预训练数据类型多样,覆盖广泛,包括大量网络文本、专业书籍…...

Java小案例-Java实现人事管理系统
前言 《人事管理系统》该项目采用技术jsp、Struts2、Mybatis、dwr、tomcat服务器、mysql数据库 开发工具eclipse/idea。 【项目使用技术】 Struts2Mybatisdwrjqueryjscss等技术 前端使用技术:JSP, dwr、jquery、js、css等 后端使用技术:Struts2Myba…...

Win系统修改Nginx配置结合内网穿透实现远程访问多个Web站点
文章目录 1. 下载windows版Nginx2. 配置Nginx3. 测试局域网访问4. cpolar内网穿透5. 测试公网访问6. 配置固定二级子域名7. 测试访问公网固定二级子域名 1. 下载windows版Nginx 进入官方网站(http://nginx.org/en/download.html)下载windows版的nginx 下载好后解压进入nginx目…...

如何使用 NFTScan NFT API 在 Base 网络上开发 Web3 应用
Base 是 Coinbase 使用 OP Stack 开发的最新以太坊第 2 层(L2)网络,用于解决以太坊等主要区块链面临的可扩展性和成本挑战。Coinbase 将其描述为“安全、低成本、对开发人员友好的以太坊 L2,旨在将下一个 10 亿用户带入 Web3”。B…...

【Chrome】ERR_SSL_PROTOCOL_ERROR问题
文章目录 前言一、下载二、使用步骤总结 前言 Edge升级最新版后,有的https访问不了,报如下错误 发现新版Chrome以及Chromium内核访问nginx ssl时报错,顺着这个思路接着查看到大佬的结论:服务器nginx使用的openssl版本过低&#…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...

STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...