为什么不应该公开用来同步的加锁对象?为什么不应该 lock(this)/lock(string) 或者 lock 任何非私...

栏目: IT技术 · 发布时间: 4年前

内容简介:如果你编写线程安全代码时为了省事儿直接不应该看看下面的两段代码。

如果你编写线程安全代码时为了省事儿直接 lock(this) ,或者早已听说不应该 lock(this) ,只是不知道原因,那么阅读本文可以帮助你了解原因。

原因

不应该 lock(this) 是因为你永远不知道别人会如何使用你的对象,永远不知道别人会在哪里加锁。于是稍不注意就可能死锁!

实例

看看下面的两段代码。

第一段是定义好的一个类,其中某个方法为了线程安全加了锁,但加锁的是 this 对象。

public class Foo
{
    public void DoSafety()
    {
        lock (this)
        {
            // 执行一些线程安全的事情。
        }
    }
}

第二段代码使用了这个类的一个实例。为了响应放到了后台线程中,但为了线程安全,加了锁。

public class Bar
{
    private readonly Foo _foo = new Foo();

    public async void DouB_Walterlv()
    {
        lock (_foo)
        {
            await Task.Run(() => _foo.DoSafety());
        }
    }
}

仔细看看这段代码,如果 DouB_Walterlv 方法执行,会发生什么?

—— 死锁

DouB_Walterlv 方法中完全看不出来为什么死锁,只能进入到 DoSafety 中才发现试图 lockthis 对象刚刚在另一个线程被 lock (_foo) 了。

扩展

从以上的例子可以看出,不止是 lock (this) 会出现“难以捉摸”的死锁问题, lock 任何公开对象都会这样。

lock 公开的属性

public class Foo
{
    public object SyncRoot { get; } = new object();
}

只要在 A 处 lock 这个对象的同时,在另一个线程调用了同样 lock 这个对象的 B 处的代码,必然死锁。

如果你试图实现某些接口中的 SyncRoot 属性,却遇到了上述矛盾(这样的写法不安全),那么可以阅读我的另一篇博客了解如何实现这样的“有问题”的接口:

lock 字符串

你可以定义一个私有的字符串,但你永远不知道这个字符串是否与其他字符串是同一个实例。因此这也是不安全的。

lock 其他任何可能被其他对象获取的公开对象

比如 Type 对象,比如其他公共静态对象。

结论

所以,一旦你决定 lock ,那么这个对象请做成 private


以上所述就是小编给大家介绍的《为什么不应该公开用来同步的加锁对象?为什么不应该 lock(this)/lock(string) 或者 lock 任何非私...》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

实现领域驱动设计

实现领域驱动设计

Vaughn Vernon / 滕云 / 电子工业出版社 / 2014-3 / 99.00元

领域驱动设计(DDD)是教我们如何做好软件的,同时也是教我们如何更好地使用面向对象技术的。它为我们提供了设计软件的全新视角,同时也给开发者留下了一大难题:如何将领域驱动设计付诸实践?Vaughn Vernon 的这本《实现领域驱动设计》为我们给出了全面的解答。 《实现领域驱动设计》分别从战略和战术层面详尽地讨论了如何实现DDD,其中包含了大量的最佳实践、设计准则和对一些问题的折中性讨论。《实......一起来看看 《实现领域驱动设计》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具