C#线程安全问题

oma*_*ase 0 c# thread-safety

如何使这个线程的代码安全?

public static class Converter
{
    public static string ConvertNameToNickname(string name)
    {
        if (name.Equals("John"))
        {
            return "Johnathon";
        }

        return name;
    }
}
Run Code Online (Sandbox Code Playgroud)

或者它是否已经是线程安全的,因为"name"是一个局部变量?我只是想确定如果ConvertNameToNickname被两个不同的线程调用,那么它正在评估的名称没有被其他线程踩到.

< - 编辑 - >

好吧,其中一些答案非常有用,但我仍然没有找到我想要的答案,所以让我稍微修改一下并提出同样的问题.给定一个mutable-type参数,如何使这段代码线程安全?或者甚至可能吗?如果我在整个方法体周围抛出一个锁{}(如例2所示),在我们进入lock语句块之前,是否仍然可以修改实例变量"name"?

public static class Converter
{
    public static string ConvertNameToNickname(StringBuilder name)
    {
        if (name.ToString().Equals("John"))
        {
            return "Johnathon";
        }

        return name;
    }
}
Run Code Online (Sandbox Code Playgroud)

例2:

private static readonly object _lockObject = new object();

public static class Converter
{
    public static string ConvertNameToNickname(StringBuilder name)
    {
        lock(_lockObject)
        {
            if (name.ToString().Equals("John"))
            {
                return "Johnathon";
            }

            return name;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ree*_*sey 7

或者它是否已经是线程安全的,因为"name"是一个局部变量?

关.它是线程安全的,但不是因为局部变量.但是,因为string在.NET中是不可变的,所以这是线程安全的.在没有同步的情况下保持线程安全的关键始终是使用不可变类型.对于可变类型,即使是类似的方法.Equals也可能不是线程安全的.

字符串是一个可变类,这不一定是线程安全的.


编辑:

好吧,其中一些答案非常有用,但我仍然没有找到我想要的答案,所以让我稍微修改一下并提出同样的问题.给定一个mutable-type参数,如何使这段代码线程安全?或者甚至可能吗?

是的,这有可能.但是,它需要某种形式的同步才是正确的.使用锁是一种选择.

如果我在整个方法体周围抛出一个锁{}(如例2所示),在我们进入lock语句块之前,是否仍然可以修改实例变量"name"?

不幸的是,确实如此.锁可以防止从两个不同的线程中同时调用此代码.从本质上讲,您正在使用"名称"线程的这种特定用途.但是,如果程序中的其他地方使用了"name",那么在锁定中使用时,仍有可能通过其他功能对其进行修改.这可能会导致微妙的竞争条件.

线程安全很难做到正确.线程安全使用可变类型的最佳选择通常是提供您自己的线程安全类型 - 其中类型本身在内部处理其所需的所有同步,并且公共API完全是线程安全的.这是保证没有其他人会"弄乱"您的数据的唯一方法,即使您正在锁定使用情况.

这是不可变类型发挥作用的地方 - 它们消除了所有这些担忧,因为它们的状态一旦创建就无法改变.任何人都可以使用它们,并构建更多,而不会对类型本身造成风险.