简体   繁体   English

String类中的线程安全性

[英]Thread safety in String class

Is it thread safe to build strings from local variables using the String class like in the methods below? 使用String类从本地变量构建字符串是否安全,如下面的方法? Suppose that the methods below are called from several threads. 假设从多个线程调用下面的方法。

public static string WriteResult(int value, string name)
{
    return string.Format("Result: value={0} name={1}", value, name);
}

public static string WriteResult2(int value, string name)
{
    return "Result: value=" + value + " name=" + name;
}

Or do I need to use StringBuilder to ensure thread safety? 或者我是否需要使用StringBuilder来确保线程安全?

That's absolutely fine. 那绝对没问题。 There is no shared state in either piece of code other than the string literals. 除了字符串文字之外,在任何一段代码中都没有共享状态。 As strings are immutable, it's fine for strings to be shared freely between threads, and both string.Format and string.Concat (implicitly called in the second piece of code) are thread-safe. 由于字符串是不可变的,因此在线程之间自由共享字符串是很好的,而string.Formatstring.Concat (在第二段代码中隐式调用)都是线程安全的。

Even if one of the parameters were mutable and even if the method mutated the parameters, eg 即使其中一个参数是可变的,即使该方法突变了参数,例如

public static void AddResult(int value, List<string> results)
{
    results.Add("Value " + value);
}

... then the method itself would still be thread-safe, so long as multiple threads didn't refer to the same List<string> . ...然后方法本身仍然是线程安全的,只要多个线程没有引用相同的List<string> If multiple threads did refer to the same List<string> then it would be unsafe even if it just read from the list, as another thread could be mutating it. 如果多个线程确实引用了相同的List<string>那么即使它只是从列表中读取它也是不安全的,因为另一个线程可能会改变它。

Both int and string as parameters in this method are effectively immutable and cannot be changed by outside code. intstring作为此方法中的参数实际上是不可变的,并且不能由外部代码更改。

So there is no need to care about thread-safety with either Format method or String.Concat in this case. 因此,在这种情况下, 无需使用Format方法或String.Concat来关心线程安全性。


But let us assume that we have some class MyObject that is mutable and can be changed from outside: 但是,让我们假设我们有一些可变的类MyObject,可以从外部更改:

public class MyClass
{
    public Int32 value1 { get; set; }
    public String value2 { get; set;}
} 

public static string WriteResult2(MyObject obj)
{
    return "Result: value=" + obj.value1 + " name=" + obj.value2 ;
}

In this case whether with first approach or second you can return inconsistent value (it both value1 and value2 are changed after one value is already put to output.) 在这种情况下,无论是第一种方法还是第二种方法,您都可以返回不一致的值(在将一个值放入输出后,value1和value2都会更改。)

As @JonSkeet pointed it is not actually the method itself that is unsafe, but the class itself is unsafe to be shared in such manner between different threads. 正如@JonSkeet 指出的那样,实际上方法本身并不安全,但是在不同线程之间以这种方式共享类本身是不安全的。

To handle this situation you will have to either create special thread-safe instance method: 要处理这种情况,您必须创建特殊的线程安全实例方法:

public class MyClass
{
    private Object lockObj = new Object();
    public Int32 value1
    {
        get
        {
            lock (this.lockObj) { ... });
        }
        set
        {
            lock (this.lockObj) { ... });
        }
    }
    public String value2
    {
        get
        {
            lock (this.lockObj) { ... });
        }
        set
        {
            lock (this.lockObj) { ... });
        }
    }

    public string WriteResult2()
    {
        lock (this.lockObj)
        {
             return "Result: value=" + this.value1 + " name=" + this.value2 ;
        }
    }
} 

Or use some additional locking over such instances in methods that use it. 或者在使用它的方法中对这些实例使用一些额外的锁定。 The first in-class approach is obviously less error-prone, but may reduce performance and create a lot of boiler-plate code. 第一个类内方法显然不易出错,但可能会降低性能并创建大量的样板代码。 Ideally, in concurrent programming the less you need to care about shared mutable state and its consistency the better . 理想情况下,在并发编程中,您需要关注共享可变状态及其一致性越少越好

Both methods are thread-safe, because it does not matter what you do inside WriteResult . 这两种方法都是线程安全的,因为在WriteResult你做什么并不重要。 As long as it does not use mutable static state, and its parameters cannot be changed from the outside, your static method is thread-safe. 只要它不使用可变静态,并且其参数不能从外部更改,您的静态方法就是线程安全的。

It is easy to verify that the methods do not use static state. 很容易验证方法不使用静态。 It is also easy to verify that method's parameters cannot be changed from outside: 验证方法的参数不能从外部更改也很容易:

  • value cannot be changed, because it is of primitive type, and it is passed by value value不能更改,因为它是原始类型,并且它是按值传递的
  • name cannot be changed, because string objects are immutable. name无法更改,因为string对象是不可变的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM