字符串属性本身是线程安全的吗?

C#中的字符串是不可变的和线程安全的。 但是当你有一个公共吸气剂属性时呢? 像这样:

public String SampleProperty{ get; private set; } 

如果我们有两个线程,第一个是调用’get’而第二个是在“相同”时调用’set’,会发生什么?

恕我直言,该集必须锁定为线程安全,如下所示:

 private string sampleField; private object threadSafer = new object(); public String SampleProperty{ get{ return this.sampleField; } private set{ lock(threadSafer){ sampleField = value; } } } 

大多数答案都使用“primefaces”这个词,就像所有需要的primefaces变化一样。 他们通常不是。

这已在评论中提及,但通常不在答案中 – 这是我提供此答案的唯一原因。 (关于以较粗粒度锁定,允许附加等内容的观点也是完全有效的。)

通常,您希望读取线程查看变量/属性的最新值。 primefaces性无法保证这一点 。 作为一个简单的例子,这是一个停止线程的方法:

 class BackgroundTaskDemo { private bool stopping = false; static void Main() { BackgroundTaskDemo demo = new BackgroundTaskDemo(); new Thread(demo.DoWork).Start(); Thread.Sleep(5000); demo.stopping = true; } static void DoWork() { while (!stopping) { // Do something here } } } 

尽管写入布尔变量是primefaces的,但DoWork可能永远循环 – 没有什么可以阻止JIT缓存在DoWorkstopping的值。 要解决此问题,您需要锁定,使变量变为volatile或使用显式内存屏障。 这也适用于字符串属性。

引用类型字段的get / set(ldfld / stfld)是(IIRC)保证是primefaces的,所以这里不应该有任何损坏的风险。 因此,从这个角度来看,它应该是线程安全的,但我个人将数据锁定在更高的级别 – 即

 lock(someExternalLock) { record.Foo = "Bar"; } 

或者可能:

 lock(record.SyncLock) { record.Foo = "Bar"; } 

这允许您对primefaces操作对同一对象进行多次读取/更新,以便其他线程无法获得无效的对象状态

设置字符串是一个primefaces操作,即你将获得新字符串或旧字符串,你永远不会得到垃圾。

如果你正在做一些工作,例如

 obj.SampleProperty = "Dear " + firstName + " " + lastName; 

然后字符串连接都发生在调用set之前,因此sampleField将始终是新字符串或旧字符串。

但是,如果您的字符串连接代码是自引用的,例如

 obj.SampleProperty += obj.SampleProperty + "a"; 

或者你在另一个线程上的位置

 obj.SampleProperty = "Initial String Value"; 

然后你需要锁。

考虑一下你正在使用int。 如果您要分配int,并且从int获得的任何值都是有效的,那么您不需要锁定它。

但是,如果int保持由两个或多个线程处理的小部件数量的计数,为了使计数准确,您需要锁定int。 字符串的情况也是如此。

我有一种感觉,我没有很好地解释这一点,希望它有所帮助。

谢谢

BW

你的第二个代码示例肯定是不对的,因为当锁在访问变量的所有地方(包括get set)使用时,锁只有所需的效果,因此get也需要锁。

但是,当获取并将引用类型字段设置为这样的属性时,添加锁定语句不会添加任何值。 在.NET环境中,指针的赋值保证是primefaces的,如果多个线程正在更改属性,那么无论如何你都有一个固有的竞争条件(线程可能看到不同的值;这可能是也可能不是问题)所以几乎没有指向锁定。

所以对于它的作用,第一段代码很好。 但是,您是否真的想要在multithreading应用程序中构建固有的竞争条件是另一回事。

这是线程安全的,无需锁定。 字符串是引用类型,因此仅修改对字符串的引用。 一个类型的引用保证是primefaces的(32位系统上的Int32和64位上的Int64)。