【问题标题】:Threads carry duplicate string objects [duplicate]线程携带重复的字符串对象[重复]
【发布时间】:2013-10-23 19:32:39
【问题描述】:

这是我的代码。在 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;
                    }
                }
            }

【问题讨论】:

  • Java 的好处是它根本不允许这样做。变量必须是最终的或实际上是最终的。

标签: c# .net multithreading


【解决方案1】:

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

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

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

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

现在这个变量在关闭后就再也不会改变了;而是为每个闭包创建一个新的 str 变量,每个闭包都有自己的变量。

【讨论】:

  • 我只是在写一些不太相似的东西:)
  • @TrevorElliott - 如果您想清理重复项,请搜索一个并投票结束此问题。
【解决方案2】:

正如 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();
    }

【讨论】:

    猜你喜欢
    • 2021-09-04
    • 2014-12-23
    • 2016-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 2011-02-26
    • 2012-10-19
    相关资源
    最近更新 更多