线程携带重复的字符串对象

本文关键字:字符串 对象 线程 | 更新日期: 2023-09-27 18:35:35

这是我的代码。 在 startLog 方法中创建的日志文件具有从 1 到 1000 的正确计数,但通过 log 方法创建的日志文件具有重复值。例如,如果重复 88,则错过 89,打印的下一个数字是 90。任何人都可以解释为什么会发生这种情况吗?

          namespace TestThreading
            {
                public partial class Form1 : Form
                {
                    NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
                    public Form1()
                    {
                        InitializeComponent();
                    }
                    private void Form1_Load(object sender, EventArgs e)
                    {
                    }
                    private void button1_Click(object sender, EventArgs e)
                    {
                        new Thread(startLog).Start();
                    }
                    private void startLog()
                    {
                        int i = 0;
                        string str;
                        while (i < 1000)
                        {
                            str = (++i).ToString();
                            logger.Trace(str);
                            Thread t = new Thread(() => log(new TestObject(str)));
                            t.Start();
                        }
                        MessageBox.Show("Done");
                    }
                    private void log(TestObject obj)
                    {
                        logger.Debug(obj.getCount());
                    }
                }
                public class TestObject
                {
                    string count;
                    public TestObject(string i)
                    {
                        count = i;
                    }
                    public string getCount()
                    {
                        return count;
                    }
                }
            }

线程携带重复的字符串对象

创建新线程时,您将关闭变量(str),然后在代码运行之前更改同一变量。

请记住,闭包关闭在变量上,而不是在 *值上。 当您的匿名方法确定要传递给log str的内容时,已经更改为另一个值。

解决方案很简单。 只需在循环内部定义str,以便每个闭包都有自己的变量来关闭:

while (i < 1000)
{
    string str = (++i).ToString();
    logger.Trace(str);
    Thread t = new Thread(() => log(new TestObject(str)));
    t.Start();
}

现在,该变量在关闭后永远不会更改;相反,为每个闭包创建一个新的str变量,并且每个闭包都有自己的变量。

正如 Servy 已经回答的那样,这是因为 str 变量是在闭包之外定义的

如果需要,您还可以使用 ParameterizedThreadStart 并在循环中传递修改的变量。这实际上会起作用

    static void Main(string[] args)
    {
        int i = 0;
        string str;
        while (i < 1000)
        {
            str = (++i).ToString();
            Thread t = new Thread((s) => Console.WriteLine(s));
            t.Start(str);
        }
        Console.ReadLine();
    }