在进行多线程开发时,如何使我们的共享数据处于被保护的状态是很重要的。
使用lock关键字可以定义一段线程同步的代码语句。
例如,
public class Printer { private object _syncRoot = new object(); public void PrintNumbers() { lock (_syncRoot) { // do something. } } }
现在我有一个共有属性Numbers,程序中的多个线程需要对它进行读写。我该如何实现同一时刻只有一个线程对其进行读写呢。请大神们赐教!!!
public class Printer { private List<string> numbers; public List<string> Numbers { get { return numbers; } set { numbers = value; } } }
既然是List,你可以使用ConcurrentBag<T>即可。
不过,你也可以根据需要使用
中任何一个。
Nice job!!!给分。
在set里加个lock(this)
set里加个lock()只是把此属性的写操作同步了,但是读操作没有同步。这样会引发状态不同步问题。比如:
假设A线程中有个循环在读取Numbers,同时B线程中有个方法在修改Numbers。这样A线程中读取的属性肯定有问题了。
@二线中的嗷嗷者: 每一次的读取都不会有问题.每一次的写入也不会有问题.
其实没有场景的讨论都是耍流氓.
你还是得描述下你的场景吧.
@吴瑞祥:
如果PrinterMonitor类的ReadNumbersAsync方法在循环读取Numbers。
碰巧此时PrinterPage类的AddNumberAsync在写Numbers,这时就有问题读取会有异常。
即便get set都加锁。在调用Numbers的get和set存取器期间,Numbers对象没有锁定,另一个线程可以获得临时值。依然没有线程安全性。
public class Printer { private static readonly object _syncRoot = new object(); private List<string> numbers; public List<string> Numbers { get { return numbers; } set { lock (_syncRoot) { numbers = value; } } } } public class PrinterMonitor { public PrinterMonitor(Printer printer) { _printer = printer; } private Printer _printer; private async Task ReadNumbersAsync() { await Task.Run(() => { _printer.Numbers.ForEach((number) => { // do something with the number. }); }); } } public class PrinterPage { public PrinterPage(Printer printer) { _printer = printer; } private Printer _printer; private async Task AddNumberAsync(string number) { await Task.Run(() => { _printer.Numbers.Add(number); // do something else... }); } }
@吴瑞祥:
在一个地方使用lock语句并不意味着,访问对象的其他线程都在等待。必须对每个访问共享状态的线程显式地使用同步功能。
@二线中的嗷嗷者: 看了人家的才明白..你不是要做一个并发安全的类.
而是要用并发安全的类.并发安全的类就是提供一些累死 addorupdate这样的方法.
你题目中的这种情况是没法的
@吴瑞祥:
我这种情况已经实现了,而且实现得很好,谢谢
@二线中的嗷嗷者: @吴瑞祥 高手啊 解释很到位 有没案例参考下呢 设计方案 思路
@亚特凯瑟琳: 最佳答案中已经给出了思路啊
@二线中的嗷嗷者: OK 看到了