List<UserModel> userList = new List<UserModel>
{
new UserModel{ UserName="jiejiep", UserAge = 26},
new UserModel{ UserName="xiaoyi", UserAge = 25},
new UserModel{ UserName="zhangzetian", UserAge=24}
};
public class TempClass
{
public UserModel um
{
get;
set;
}
public void ShowMessage(object obj)
{
Thread.Sleep(1000);
MessageBox.Show(um.UserName);
}
}
复制代码
复制代码
TempClass tempCls = new TempClass();
foreach (var u in userList)
{
tempCls.um = u;
ThreadPool.QueueUserWorkItem((obj) =>
{
tempCls.ShowMessage(obj);
});
}
调试结果和运行结果不同,能不能给我解释一下
不是调试和运行的区别,而是你这段代码本身就不是线程安全的。
也就是说语句 tempCls.um = u 和 MessageBox.Show(um.UserName) 并不是按照 foreach (var u in userList) 顺序来执行的,而是乱序执行。
还是不太理解,能不能介绍的详细一点
调试的时候运行结果:jiejiep,xiaoyi,zhangzetian
运行记得结果:zhangzetian,zhangzetian,zhangzetian
我基础不太好!
@博学多思: 如果我说语句 ThreadPool.QueueUserWorkItem((obj) =>
{
tempCls.ShowMessage(obj);
}) 不会阻塞调用线程,你能明白吗?
@Launcher: 我对线程一无所知,但是我昨天研究了一天也觉得是ThreadPool.QueueUserWorkItem((obj) =>
{
tempCls.ShowMessage(obj);
})的问题,但是原理还是不懂
@博学多思: 如果你对线程都一无所知的话,那烦请你先找本《操作系统》的书学习下。
也就是说语句 tempCls.um = u 和 MessageBox.Show(um.UserName) 并不是按照 foreach (var u in userList) 顺序来执行的,而是乱序执行。
既然是乱序执行,为什么每次运行的结果都相同?
ThreadPool.QueueUserWorkItem((obj) =>
{
tempCls.ShowMessage(obj);
}) 不会阻塞调用线程
就是把这个方法将方法排入队列以便执行。 方法在有线程池线程变得可用时执行
@Launcher: MoveNext or Reset throws an InvalidOperationException.">枚举数没有对集合的独占访问权;因此,从头到尾对一个集合进行枚举在本质上不是一个线程安全的过程。 MoveNext and Current, Current returns the element that it is set to, even if the enumerator is already invalidated.">即使某个集合已同步,其他线程仍可以修改该集合,这会导致枚举数引发异常。 若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常
还是这个原因?
@博学多思: 既然是乱序执行,为什么每次运行的结果都相同? ——〉 这确实能证明你对线程一无所知。
和枚举没关系,就是简单的多线程问题。
@Launcher: 乱序执行:避免因为获取下一条程序指令所引起的处理器等待,取而代之的处理下一条可以立即执行的指令
当程序运行到: ThreadPool.QueueUserWorkItem((obj) =>
{
tempCls.ShowMessage(obj);
});
的时候,是直接运行下一次循环吗?求指教?当整个循环完事然后运行 ThreadPool.QueueUserWorkItem((obj) =>
{
tempCls.ShowMessage(obj);
});?对不对?
@博学多思: 不是,是执行完 ThreadPool.QueueUserWorkItem 方法后执行 foreach (var u in userList) 语句。
@Launcher: 大侠,程序执行的顺序是不是这样:当程序运行到 tempCls.um = u; ThreadPool.QueueUserWorkItem(方法排入队列以便执行。 方法在有线程池线程变得可用时执行)新线程立即处理 tempCls.ShowMessage(obj);调用 Thread.Sleep(1000);
MessageBox.Show(um.UserName);原来的线程继续执行foreach 语句,因为变量在内部,所以最后只有一个值,这时重新排列单元将各执行单元结果按指令顺序重新排列,所以输出好几条zhangzetian???
@博学多思: 正确。
@Launcher: 非常感谢!
这是闭包的结果
foreach (var u in userList)
{
TempClass tempCls = new TempClass();
tempCls.um = u;
ThreadPool.QueueUserWorkItem((obj) =>
{
tempCls.ShowMessage(obj);
});
}
你再看看
这个就是我学习闭包的时候发现的问题,我不明白为什么调试和运行的结果不同?
@博学多思: 大哥 调试走的表象啊,跟没看是一样的,实际代码去看IL