为什么不应该公开用来同步的加锁对象?为什么不应该 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 任何非私...》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

近似算法

近似算法

瓦齐拉尼 / 2010-9 / 49.00元

《近似算法》系统总结了到本世纪初为止近似算法领域的成果,重点关注近似算法的设计与分析,介绍了这个领域中最重要的问题以及所使用的基本方法和思想。全书分为三部分:第一部分使用不同的算法设计技巧给出了下述优化问题的组合近似算法:集合覆盖、施泰纳树和旅行商、多向割和k-割、k-中心、反馈顶点集、最短超字符串、背包、装箱问题、最小时间跨度排序、欧几里得旅行商等。第二部分介绍基于线性规划的近似算法。第三部分包......一起来看看 《近似算法》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具