循环变量在线程赋值中的异常问题及原因咨询
线程循环变量捕获问题解析
问题场景
需要将10个任务分配到独立线程执行,线程中使用循环变量i给数组指定位置赋值(已加锁),出现数组越界错误:调试发现最后一次循环中i的值为10(预期应为9),单线程场景下无此问题。
三种代码尝试:
- 直接使用循环变量
i(报错):
for(int i = 0; i<10; i++) { Thread t = new Thread (() => {/* 业务逻辑,使用变量i */}); }
- 线程内部赋值局部变量
localI(仍报错):
for(int i = 0; i<10; i++) { Thread t = new Thread (() => { int localI = i; /* 业务逻辑,使用localI */ }); }
- 线程创建前赋值
localI(正常运行):
for(int i = 0; i<10; i++) { int localI = i; Thread t = new Thread (() => { /* 业务逻辑,使用localI */ }); }
原因解析
核心在于闭包捕获的是变量的引用,而非当前值:
第一种写法中,所有线程的Lambda表达式捕获的是同一个循环变量
i的引用。循环执行速度远快于线程启动,等线程真正开始执行时,i已经循环到10,自然触发数组越界。第二种写法里,
localI = i是在线程执行时才会运行。此时循环早就完成,i的值已经是10,赋值给localI的也是10,问题没有解决。第三种写法中,
localI = i在循环的每一次迭代中执行,每次迭代都会创建一个新的localI变量,捕获的是当前迭代的i的副本值。线程启动时捕获的是这个独立的localI的引用,每个线程拿到的都是对应迭代的正确数值,不会被后续循环的i值覆盖。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

