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

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

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

如果你编写线程安全代码时为了省事儿直接 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 任何非私...》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

大数据时代的IT架构设计

大数据时代的IT架构设计

IT架构设计研究组 / 电子工业出版社 / 2014-4 / 49.00元

《大数据时代的IT架构设计》以大数据时代为背景,邀请著名企业中的一线架构师,结合工作中的实际案例展开与架构相关的讨论。《大数据时代的IT架构设计》作者来自互联网、教育、传统行业等领域,分享的案例极其实用,代表了该领域较先进的架构。无论你就职于哪一行业都可以从本书中找到相关的架构经验,对您在今后的架构设计工作中都能起到很好的帮助作用。 《大数据时代的IT架构设计》适合具备一定架构基础和架构经验......一起来看看 《大数据时代的IT架构设计》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码

MD5 加密
MD5 加密

MD5 加密工具