在这个方法中,int
和string
参数都是有效的不可变对象,不能被外部代码更改。
因此,在这种情况下,无需关心Format方法或String.Concat的线程安全性。
假设我们有一个可变的类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 ;
}
在这种情况下,无论是第一种方法还是第二种方法,都可能返回不一致的值(如果一个值已经被放入输出后,value1和value2都被更改)。
正如@JonSkeet所
指出的那样,实际上并不是方法本身不安全,而是类本身不安全,在不同线程之间共享时不安全。
要处理这种情况,您将需要创建特殊的线程安全实例方法:
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 ;
}
}
}
使用方法中对这些实例进行额外的锁定。显然,第一个类内方法更少出错,但可能会降低性能并创建大量样板代码。理想情况下,在并发编程中,您需要关心共享可变状态及其一致性的越少
越好。
WriteResult2
方法内部再加锁呢? - Jenish RabadiyaWriteResult
方法内部,value1
和value2
的值必须保持一致 - 在构建输出字符串时不能更改这些值。例如,当value1
=Jenish,value2
=Rabadiya 时,我们调用WriteResult
,它会写入 Jenish,但是外部代码同时将value2
更改为 Podskal。显然这不是我们想要的结果。尽管在调用WriteResult
之前允许我们创建这种不一致的状态,但我们应该删除两个 setter 并为这两个属性创建一个同步 setter 方法。或者使用不可变类型。 - Eugene Podskal