for循环中创建线程执行问题
先执行以一个简单的示例:
static void Main(string[] args) {
List<int> taskConsumes = new List<int>() { 1,2,3,4,5};
for (int i = 0; i < taskConsumes.Count; i++)
{
new Task(() => {
TaskMethod(taskConsumes[i]);
}).Start();
}
Console.ReadLine();
}
public static void TaskMethod(int index)
{
Console.WriteLine(index);
}
执行结果:

直接异常了,按照常理不应该呀,我们再将原理的代码改一下看看结果如何
我们先来创建执行线程代码,然后在写输出代码:
static void Main(string[] args)
{
new Task(() =>
{
TaskMethod(1);
}).Start();
Console.WriteLine("输出内容");
Console.ReadLine();
}
输出结果:

由此我们可以得出一个结论,就是:创建执行Task.Run()是在另外一个子线程中执行的,他的创建+执行需要消耗一定的时间,而主线程方法是不会受Task的影响,他会直接执行
因此,我们最初的代码中,for循环 0到taskConsumes.Count,很快就会执行完成。当他执行完成最后的 i 其实不是taskConsumes.Count-1(因为for是 i++形式),而是

所以,在执行子线程的时候,其实就是去拿taskConsumes[5],准定就超出索引异常了。
那现在我们如果不想让程序出错的执行,给他改一下代码:
static void Main(string[] args)
{
List<int> taskConsumes = new List<int>() { 1, 2, 3, 4, 5 };
for (int i = 0; i < taskConsumes.Count; i++)
{
int indexI = i;
new Task(() =>
{
TaskMethod(taskConsumes[indexI]);
}).Start();
}
Console.ReadLine();
}
执行结果:

这样,我们在for中创建一个临时变量indexI,每个工作域中的i都赋予了局部变量indexI,Task中的变量就是局部变量indexI了,而不是for的全部变量i,程序也就达到了我们想要的效果了(另外Task子线程中执行顺序也不是顺序执行的)。
for循环中创建线程执行问题的更多相关文章
- java 中创建线程有哪几种方式?
Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行 ...
- JAVA中创建线程的三种方法及比较
JAVA中创建线程的方式有三种,各有优缺点,具体如下: 一.继承Thread类来创建线程 1.创建一个任务类,继承Thread线程类,因为Thread类已经实现了Runnable接口,然后重写run( ...
- Java中创建线程的三种方式以及区别
在java中如果要创建线程的话,一般有3种方法: 继承Thread类: 实现Runnable接口: 使用Callable和Future创建线程. 1. 继承Thread类 继承Thread类的话,必须 ...
- 在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程!(更好的管理异常)
在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程! 如果直接使用Win32的API函数CreateThread()创建多个线程,也是可以创建的.但 ...
- JAVA中创建线程池的五种方法及比较
之前写过JAVA中创建线程的三种方法及比较.这次来说说线程池. JAVA中创建线程池主要有两类方法,一类是通过Executors工厂类提供的方法,该类提供了4种不同的线程池可供使用.另一类是通过Thr ...
- C++类中创建线程
经常会遇到需要在类中创建线程,可以使用静态成员函数,并且将类实例的指针传入线程函数的方式来实现. 实现代码代码如下: /* 类头文件 CTestThread.h */ #include<io ...
- 【java并发】传统线程技术中创建线程的两种方式
传统的线程技术中有两种创建线程的方式:一是继承Thread类,并重写run()方法:二是实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread.这两种方式 ...
- linux内核中创建线程方法
1.头文件 #include <linux/sched.h> //wake_up_process() #include <linux/kthread.h> //kthread_ ...
- Java中创建线程的两种方式
创建线程的第一种方式: 创建一个类继承Thread 重写Thread中的run方法 (创建线程是为了执行任务 任务代码必须有存储位置,run方法就是任务代码的存储位置.) 创建子类对象,其实就是在创建 ...
随机推荐
- VS 2019下载、安装与注册包含MF、界面美化和安装Visual Assist
下载: 1.在搜索框中输入"微软" 2. 3. 安装: 1.双击运行-继续-等待安装完成 2. 3.安装完后,重启电脑,并创建快捷方式. 注册: 1.打开软件 2. 3. 4.网上 ...
- MySQL修改root密码的多种方法, mysql 导出数据库(包含视图)
方法1: 用SET PASSWORD命令 mysql -u root mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpass ...
- Zookeeper原理系列-Paxos协议的原理和Zookeeper中的应用分析
Paxo算法介绍 Paxos算法是莱斯利·兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法. Paxos产生背景 Paxos算法是基于消息传递且具有高度容错特性的一致 ...
- 单机百万连接调优和Netty应用级别调优
作者:Grey 原文地址:单机百万连接调优和Netty应用级别调优 说明 本文为深度解析Netty源码的学习笔记. 单机百万连接调优 准备两台Linux服务器,一个充当服务端,一个充当客户端. 服务端 ...
- 《面试八股文》之 JVM 20卷
微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. <面试八股 ...
- 查询windows日志
系统日志可以用来查看系统的一些信息,比如警告.错误.验证.开关机等. 打开系统日志 按下快捷键win+R,输入eventvwr.exe,并点击确定 查询开关机记录 点击左侧Windows日志-> ...
- SphereEx 登陆 ApacheCon Asia|依托 ShardingSphere 可插拔架构体系打造数据应用完整生态
2021 年 8 月 8 日,ApacheCon 首次亚洲大会于线上正式闭幕.作为久负盛名的开源盛宴,本届 ApacheCon Asia 受到了海内外众多开源领域人士的关注. 作为 Apache 软件 ...
- 技术番外篇丨Github Action CI/CD
起源 看到.Net群里再聊CI/CD,我就这里分享一下我目前自己一些小东西的做法,我目前在Github有一个自己私有的组织,里面存放了我的部分商业化项目,早期我采用Jenkins用Webhooks进行 ...
- 题解 2020.10.24 考试 T3 数列
题目传送门 题目大意 给出一个数 \(n\),你要构造一个数列,满足里面每个数都是 \(n\) 的因子,且每一个数与前面不互质的个数不超过 \(1\).问有多少种合法方案. 保证 \(n\) 的不同质 ...
- windows右键菜单自动打包发布nuget,没有CI/CD一样方便!
构建现代的 .Net 应用离不开 Nuget 的支持,而快速打包 Nuget 成了提高生产率的有效方法.没有CI/CD?来试试使用windows右键菜单吧 先看右键效果图 有时候我们可能没有CI/CD ...