这是我的代码:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 200; i++)
{
Console.WriteLine("---------" + i.ToString());
Demo.TestError();
}
}
public class Demo
{
public Demo() { }
public Demo(int i) { index = i; }
public static void TestError()
{
List<Thread> threads = new List<Thread>();
Demo demo = null;
for (int i = 0; i < 1000; i++)
{
if (i % 10 == 0)
{
demo = new Demo(i);
}
#region code1
Thread t = new Thread(() =>
{
demo.SetName();
var names = demo.names;
string msg = null;
if (names == null)
{
msg = demo.index.ToString() + " -" + Thread.CurrentThread.ManagedThreadId.ToString() + "-is null";
Console.Write(msg);
}
else if (names == null || names.Count <= 0)
{
msg = demo.index.ToString() + " -" + Thread.CurrentThread.ManagedThreadId.ToString() + "-is zero";
Console.Write(msg);
}
else
{
msg = demo.index.ToString() + " -" + Thread.CurrentThread.ManagedThreadId.ToString() + "-is ok" + "-" + string.Join(",", names);
}
});
t.Start();
#endregion
threads.Add(t);
}
for (int i = 0; i < threads.Count; i++)
{
threads[i].Join();
}
}
public List<string> names;
public int index;
public object lockObj = new object();
public void SetName()
{
if (names == null)
{
lock (lockObj)
{
if (names == null)
{
var tnames = new List<string>();
tnames.Add("a");
System.Threading.Interlocked.CompareExchange(ref names, tnames, null);
}
}
}
}
}
运行它,它显示(部分):
--------- 60 750 -747-无效--------- 61 --------- 62
...
--------- 95 960 -5174-null null --------- 96 --------- 97
...
--------- 101 580 -3591-is null --------- 102 --------- 103
...
--------- 112 720 -2193 - 为空--------- 113 --------- 114
...
--------- 123 50 -2790-is null --------- 124 --------- 125
...
--------- 133 420 -1237-为空--------- 134 --------- 135
...
将code1更改为code2:
#region code2
Thread t = new Thread((obj) =>
{
var d = obj as Demo;
d.SetName();
var names = d.names;
...//the same as above
});
t.Start(demo);
#endregion
它运行成功!那么
之间的区别是什么public Thread(ThreadStart start);
和
public Thread(ParameterizedThreadStart start);
?为什么demo.names
为空或其计数为零?
答案 0 :(得分:1)
他们的唯一不同之处在于ParameterizedThreadStart
获取了一个对象作为输入,但ThreadStart
并不是那么简单。
那么为什么其中一个有效,另一个无效呢?这是因为你的范围可变。使用ParameterizedThreadStart
后,它会将demo
变量作为参数传递,因此当for
循环迭代到下一次运行时,它不会更改其引用,而在第一个代码中您正在使用相同的对象并在所有线程之间共享它。
主要问题是您已在demo
块之外定义了for
变量。因此,当您更改变量的引用(演示)时,正在发生竞争条件在循环中轻快,但它仍然在你的线程中使用。
Demo demo = null;
for (int i = 0; i < 1000; i++)
{
if (i % 10 == 0)
{
demo = new Demo(i);
}
...
}
如果您将代码更改为此代码,它应该得到修复并适用于两种情况:
for (int i = 0; i < 1000; i++)
{
Demo demo = null;
if (i % 10 == 0)
{
demo = new Demo(i);
}
...
}
答案 1 :(得分:0)
我知道为什么code1在
中获取demo.names == null if (i % 10 == 0)
{
demo = new Demo(i);
}
#region code1
Thread t = new Thread(() =>
{
demo.SetName();
var names = demo.names;
当thread1运行到demo.SetName()时,它将demo.names设置为null,但是thread2运行到demo = new Demo(i),它将demo.names设置为null,然后var names = demo.names它获取demo.names null,但现在demo是与demo.SetName()的不同实例。 @akazemis谢谢你!