C# 使用多线程的几种方式
1.Thread
详细介绍:https://www.cnblogs.com/cheng8/p/16147918.html
使用Thread类通过ThreadStart(无参数)或ParameterizedThreadStart(一个输入参数)类型的委托创建一个Thread对象,开启一个新线程,执行该委托传递的任务,此时线程尚未处于运行状态。调用Start()函数启动线程,当前线程继续执行。调用Join()函数可以阻塞当前线程,直到调用Join()的线程终止。
Thread类创建的线程默认为前台线程,可以通过IsBackground属性设置其为前台或后台线程。还可以通过Priority属性设置线程的优先级。
如需中止线程,调用Abort()方法,在调用该方法的线程上抛出ThreadAbortException异常,以结束该线程。线程内部可以通过try catch捕获该异常,在catch模块中进行一些必要的处理,如释放持有的锁和文件资源等,还可以通过Thread.ResetAbort()方法阻止线程的中止。但是通常来说,应当慎重使用Abort()方法,如果在当前线程中抛出该异常,其结果是可预测的,但是对于其他线程,它会中断任何正在执行的代码,有可能中断静态对象的生成,造成不可预测的结果。
Thread thread = new Thread(() =>
{
Console.WriteLine("Hello");
});
thread.Start();
Console.ReadKey();
2.线程池
但是线程池的使用也有一些限制:
- 线程池中的线程均为后台线程,并且不能修改为前台线程
- 不能给入池的线程设置优先级或名称
- 对于COM对象,入池的所有线程都是多线程单元(MTA)线程,许多COM对象都需要单线程单元(STA) 线程
- 入池的线程只适合时间较短的任务,如果线程需要长时间运行,应使用Thread类创建线程或使用Task的LongRunning选项
for (int i = 0; i < 5; ++i)
ThreadPool.QueueUserWorkItem(Do); Console.ReadKey(); static void Do(Object o)
{
for (int i = 0; i < 3; i++)
Console.WriteLine("loop:{0}, thread id: {1}", i, Thread.CurrentThread.ManagedThreadId);
}
3.Parallel类
Parallel和Task类都位于System.Threading.Task命名空间中,是对Thread和ThreadPool类更高级的抽象。Parrallel类有For()、ForEach()、Invoke()三个方法,前两者在每次迭代中调用相同的代码,实现了数据并行性,Invoke()允许同时调用不同的方法,实现任务并行性。
For()和ForEach()两者的用法类似。如下例,调用Parallel.For()方法,实现从0到10的迭代,每次迭代是并行执行的,并且从输出结果可以看出,执行顺序是不能保证的。
ParallelLoopResult result = Parallel.For(0, 10, i =>
{
Console.WriteLine("i:{0}, thread id: {1}", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
}); Console.WriteLine("Is completed: {0}", result.IsCompleted);
Console.ReadKey();
通过ParallelLoopState的Break()或Stop()方法,可以提前中断Parallel.For()的迭代。
ParallelLoopResult result = Parallel.For(0, 100, (i, state) =>
{
Console.WriteLine("i:{0}, thread id: {1}", i, Thread.CurrentThread.ManagedThreadId); if (i > 10)
state.Break(); Thread.Sleep(10);
}); Console.WriteLine("Is completed: {0}", result.IsCompleted);
Console.WriteLine("Lowest break iteration: {0}", result.LowestBreakIteration);
Console.ReadKey();
如需同时执行多个不同的任务,可以使用Parallel.Invoke()方法,它允许传递一个Action委托数组。
Parallel.Invoke(Func1, Func2, Func3);
4.Task类
启动任务
TaskFactory tf = new TaskFactory();
Task t1 = tf.StartNew(TaskMethod.DoTask, "using a task factory"); Task t2 = Task.Factory.StartNew(TaskMethod.DoTask, "factory via a task"); Task t3 = new Task(TaskMethod.DoTask, "using a task constructor and start");
t3.Start(); var t4 = Task.Run(() => TaskMethod.DoTask("using Run method")); Console.ReadKey(); class TaskMethod
{
static object taskLock = new object();
public static void DoTask(object msg)
{
lock (taskLock)
{
Console.WriteLine(msg);
Console.WriteLine("Task id:{0}, Thread id :{1}",
Task.CurrentId == null ? "no task" : Task.CurrentId.ToString(),
Thread.CurrentThread.ManagedThreadId);
}
}
}
接收任务的返回值
对于任务有返回值的情况,可使用Task<TResult>泛型类,TResult定义了返回值的类型,以下代码演示了调用返回int值的任务的方法。
var t5 = new Task<int>(TaskWithResult, Tuple.Create<int, int>(1, 2));
t5.Start();
t5.Wait();
Console.WriteLine("adder results: {0}", t5.Result); Console.ReadKey(); static int TaskWithResult(object o)
{
Tuple<int, int> adder = (Tuple<int, int>)o;
return adder.Item1 + adder.Item2;
}
同步调用
调用Task类的RunSynchronously()方法,可以实现同步调用,直接在当前线程上调用该任务。
TaskMethod.DoTask("Just Main thread");
Task t1 = new Task(TaskMethod.DoTask, "using Run Sync");
t1.RunSynchronously(); class TaskMethod
{
static object taskLock = new object();
public static void DoTask(object msg)
{
lock (taskLock)
{
Console.WriteLine(msg);
Console.WriteLine("Task id:{0}, Thread id :{1}",
Task.CurrentId == null ? "no task" : Task.CurrentId.ToString(),
Thread.CurrentThread.ManagedThreadId);
}
}
}
指定连续任务
TaskFactory tf = new TaskFactory();
Task t1 = tf.StartNew(() =>
{
Console.WriteLine("Current Task id = {0}", Task.CurrentId);
Console.WriteLine("执行任务1\r\n");
Thread.Sleep(10);
}); Task t2 = t1.ContinueWith((t) =>
{
Console.WriteLine("Last Task id = {0}", t.Id);
Console.WriteLine("Current Task id = {0}", Task.CurrentId);
Console.WriteLine("执行任务2\r\n");
Thread.Sleep(10);
}); Task t3 = t2.ContinueWith(delegate (Task t)
{
Console.WriteLine("Last Task id = {0}", t.Id);
Console.WriteLine("Current Task id = {0}", Task.CurrentId);
Console.WriteLine("执行任务3\r\n");
}, TaskContinuationOptions.OnlyOnRanToCompletion); Console.ReadKey();
对于ContinueWith()的使用,MSDN演示了更加优雅的“流式”调用方法:
var backgroundScheduler = TaskScheduler.Default;
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(delegate { DoBackgroundComputation(); },
backgroundScheduler).
ContinueWith(delegate { UpdateUI(); }, uiScheduler).
ContinueWith(delegate { DoAnotherBackgroundComputation(); },
backgroundScheduler).
ContinueWith(delegate { UpdateUIAgain(); }, uiScheduler);
5.BackgroundWorker控件
C# 使用多线程的几种方式的更多相关文章
- c#使用多线程的几种方式示例详解
本文转载自:http://www.jb51.net/article/46234.htm 本文章主要介绍了c#使用多线程的几种方式,通过示例学习c#的多线程使用方式,大家参考使用吧 (1)不需要传递参数 ...
- Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式
概要 本章,我们学习“常用的实现多线程的2种方式”:Thread 和 Runnable.之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多线程.关于线程 ...
- java多线程系类:基础篇:02常用的实现多线程的两种方式
本章,我们学习"常用的实现多线程的2种方式":Thread 和 Runnable.之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多 ...
- Java实现多线程的两种方式
实现多线程的两种方式: 方式1: 继承Thread类 A: 自定义MyThread类继承Thread类 B: 在MyThread类中重写run() C: 创建MyThread类的对象 D: 启动线程对 ...
- c# 多线程的几种方式
1.什么是线程? 进程作为操作系统执行程序的基本单位,拥有应用程序的资源,进程包含线程,进程的资源被线程共享,线程不拥有资源. 2.前台线程和后台线程的区别? 程序关闭时,后台线程直接关闭,但前台线程 ...
- 创建多线程的第一种方式——创建Thread子类和重写run方法
创建多线程的第一种方式——创建Thread子类和重写run方法: 第二种方式——实现Runnable接口,实现类传参给父类Thread类构造方法创建线程: 第一种方式创建Thread子类和重写run方 ...
- Java实现多线程的三种方式
Java多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.前两种方式启动的线程没有返回值 ...
- Java中实现多线程的四种方式
Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorService.Cal ...
- Java中实现多线程的两种方式之间的区别
Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线 ...
- JAVA实现多线程的四种方式
JAVA多线程实现方式: 1.继承Thread类(无返回值) 2.实现Runnable接口(无返回值) 3.实现Callable接口,通过FutureTask包装器来创建Threak线程(有返回值) ...
随机推荐
- 20230103~05code
目录 U190849 最简分式 P5734 [深基6.例6]文字处理软件 P1104 生日 P4305 [JLOI2011]不重复数字 P8218 [深进1.例1]求区间和 P3397 地毯 P236 ...
- rancher 修改域名
rancher 修改域名 rancher 修改ingress.nginx 对应的域名后 cattle-system 名称空间下的pod 依然是连接旧环境的rancher 域名 解决办法 1. 需要登录 ...
- Python语言基础实验(第四周)
Python语言基础实验(第四周) 一.实验目的 1.了解并掌握python中序列及序列的常用操作. 2.根据实际需要运用合适的序列类型来完成实验. 二.实验环境 软件版本:Python 3.10 6 ...
- Java复习篇3---基础概念
关键字 关键字:被Java赋予了特定含义的英文单词 关键字的字母全是小写 常用的代码编辑器,针对关键字会有特殊的颜色标记,非常直观 例如: class: 用于(创建\定义)一个类,后面紧跟类名. 类是 ...
- Pytest 固件
一.固件使用背景 在执行测试用例时,我们常常需要在测试用例执行的前后去完成一些额外的操作.例如针对于 Web 测试,在用例执行前需要打开浏览器,完成用户登录等一系列前置操作:在用例执行完成后,要清除浏 ...
- win10 扩展c盘 “PARTITION_BASIC_DATA_GUID"
一不小心化身为c盘战士了,系统卡到不行 于是通过pe登入系统(我自己用的wintogo),然后下载傲梅分区助手(嘎嘎好用) 傲梅官网 https://www.disktool.cn/download. ...
- 初学银河麒麟linux笔记 第五章 windows中开发的QT程序适配linux的修改——外部控件重新调用
本人在WINDOWS系统中使用了"飞扬青云"的控件 https://gitee.com/feiyangqingyun/QUCSDK 由于系统移植,调用库应改为linux系统,首先下 ...
- Gitbook部署
title: Gitbook部署 # 标题 date: 2020-06-14 08:00:00 借助Gitbook,写自己的第一本电子书 Gitbook部署 一.电脑环境 Git 环境,我的电脑上已经 ...
- [Docker-2]排查基于docker部署mysql主从过程中遇到“Slave_IO_Running: Connecting”这个疑难杂症
关于"Slave_IO_Running: Connecting"的排查方法,已经有很多博客写得清清楚楚了(很多都是复制粘贴..真浪费时间),那么如果已有的常规排查方法都不能解决你的 ...
- robots.txt 文件说明
robots其实就是指Robots协议,Robots协议(也称为爬虫协议.机器人协议等)的全称是"网络爬虫排除标准"(Robots Exclusion Protocol),网站通过 ...