`

关于lock(this)的说明及用法

    博客分类:
  • C#
阅读更多

一. 为什么要lock,lock了什么?

当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待。但当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进行读写的时候,我们要使该资源在同一时刻只能被一个线程操作,以确保每个操作都是有效即时的,也即保证其操作的原子性。lock是C#中最常用的同步方式,格式为lock(objectA){codeB} 。

lock(objectA){codeB} 看似简单,实际上有三个意思,这对于适当地使用它至关重要:
1. objectA被lock了吗?没有则由我来lock,否则一直等待,直至objectA被释放。
2. lock以后在执行codeB的期间其他线程不能调用codeB,也不能使用objectA。
3. 执行完codeB之后释放objectA,并且codeB可以被其他线程访问。

二. lock(this)怎么了?

我们看一个例子:

 

using System;
using System.Threading;

namespace Namespace1
{
    class C1
    {
        private bool deadlocked = true;

        //这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
        public void LockMe(object o)
        {
            lock (this)
            {
                while(deadlocked)
                {
                    deadlocked = (bool)o;
                    Console.WriteLine("Foo: I am locked :(");
                    Thread.Sleep(500);
                }
            }
        }

        //所有线程都可以同时访问的方法
        public void DoNotLockMe()
        {
            Console.WriteLine("I am not locked :)");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            C1 c1 = new C1();

            //在t1线程中调用LockMe,并将deadlock设为true(将出现死锁)
            Thread t1 = new Thread(c1.LockMe);
            t1.Start(true);
            Thread.Sleep(100);

            //在主线程中lock c1
            lock (c1)
            {
                //调用没有被lock的方法
                c1.DoNotLockMe();
                //调用被lock的方法,并试图将deadlock解除
                c1.LockMe(false);
            }
        }
    }

        在t1线程中,LockMe调用了lock(this), 也就是Main函数中的c1,这时候在主线程中调用lock(c1)时,必须要等待t1中的lock块执行完毕之后才能访问c1,即所有c1相关的操作都无法完成,于是我们看到连c1.DoNotLockMe()都没有执行。

      把C1的代码稍作改动:

    class C1
    {
        private bool deadlocked = true;
        private object locker = new object();

        //这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
        public void LockMe(object o)
        {
            lock (locker)
            {
                while(deadlocked)
                {
                    deadlocked = (bool)o;
                    Console.WriteLine("Foo: I am locked :(");
                    Thread.Sleep(500);
                }
            }
        }

        //所有线程都可以同时访问的方法
        public void DoNotLockMe()
        {
            Console.WriteLine("I am not locked :)");
        }
    }
 这次我们使用一个私有成员作为锁定变量(locker),在LockMe中仅仅锁定这个私有locker,而不是整个对象。这时候重新运行程序,可以看到虽然t1出现了死锁,DoNotLockMe()仍然可以由主线程访问;LockMe()依然不能访问,原因是其中锁定的locker还没有被t1释放。



关键点:
1. lock(this)的缺点就是在一个线程(例如本例的t1)通过执行该类的某个使用"lock(this)"的方法(例如本例的LockMe())锁定某对象之后, 导致整个对象无法被其他线程(例如本例的主线程)访问 - 因为很多人在其他线程(例如本例的主线程)中使用该类的时候会使用类似lock(c1)的代码。
2. 锁定的不仅仅是lock段里的代码,锁本身也是线程安全的。
3. 我们应该使用不影响其他操作的私有对象作为locker。
4. 在使用lock的时候,被lock的对象(locker)一定要是引用类型的,如果是值类型,将导致每次lock的时候都会将该对象装箱为一个新的引用对象(事实上如果使用值类型,C#编译器(3.5.30729.1)在编译时就会给出一个错误)。

 

分享到:
评论
1 楼 jiazhigang 2012-08-09  
引用
即所有c1相关的操作都无法完成,于是我们看到连c1.DoNotLockMe()都没有执行。

这句解释碉堡了...

相关推荐

    lock(this)的使用说明

    "lock(this)的使用说明" lock(this)是C#语言中的一种同步机制,用于确保在多线程环境下对共享资源的访问安全。通过使用lock(this)语句,可以保证在同一时刻只有一个线程可以访问某个资源,防止多个线程同时访问同...

    c#线程 lock用法

    初始的尝试是使用`lock(this)`,但由于每个邮箱实例都有自己的`this`引用,所以这无法达到预期效果。正确的做法是锁定一个所有线程都能识别的同一对象,这里我们创建了一个静态变量`syncRoot`: ```csharp public ...

    C# lock一个简单实例

    在探讨"C# lock一个简单实例"这一...掌握了`lock`的正确使用方法,可以帮助开发者编写出更健壮、更高效的并发程序。然而,需要注意的是,锁的使用并非没有代价,合理的锁策略对于构建高性能的多线程应用程序至关重要。

    c#lock 演示代码

    在这个例子中,`Counter`类有一个`Increment`方法,它内部使用了`lock`来确保每次只有一个线程能够执行`count++`操作。`this`作为锁对象,意味着同一实例的任何`lock`块都会互斥执行,防止了两个线程同时增加计数器...

    C#中lock用法详解

    下面我们将深入探讨`lock`的用法和工作原理。 首先,`lock`语句的语法结构如下: ```csharp lock (expression) { // 代码块 } ``` 这里的`expression`应该是一个引用类型的变量,它用于确定要锁定的对象。当线程...

    numLock.zip

    SYMPTOMS When you start EXCEL 2010, the NumLock key state is off. But also sometimes the Num...锁定数字键盘使用方法: 解压文件numLock.zip到 c:\numLock 运行 numlock.exe,可以创建快捷方式,放到启动文件夹.

    c# 线程同步: 详解lock,monitor,同步事件和等待句柄以及mutex

    然而,使用lock时需要注意,不要锁定public类型的实例,如`lock(this)`,因为这可能导致不可预见的外部访问。更安全的做法是锁定一个私有的静态成员变量,以限制锁定的范围。例如: ```csharp private static ...

    C#中实现线程同步lock关键字的用法详解

    本文将详细讲解`lock`关键字的使用方法和注意事项。 1. **什么是`lock`关键字?** `lock`关键字是一个语句块,它确保在同一时间只有一个线程能够执行被锁定的代码块。这背后的工作原理是通过获取和释放对象的互斥...

    C#中volatile与lock用法

    1. **工作原理**:当一个线程进入`lock`代码块并执行时,它会获得`thisLock`对象的锁。其他尝试进入的线程会被阻塞,直到当前线程执行完毕并释放锁。 2. **使用场景**:`lock`常用于保护对共享资源的访问,确保多...

    lock4j-master.zip

    try (Lock lock = this.lock.lock("myLockKey")) { if (lock.locked()) { // 业务逻辑 } else { // 锁获取失败处理 } } catch (InterruptedException e) { // 处理中断异常 } } } ``` 五、Lock4j 的...

    Laravel开发-illuminate-lock

    通过使用"illuminate-lock",开发者可以避免竞态条件,提高应用程序的稳定性和可靠性。 二、Symfony Lock组件 Symfony的Lock组件是"illuminate-lock"的基础,它提供了一套强大的工具来创建可持久化的锁,支持多种...

    Synchronized 和 Lock 的区别和使用场景

    3. 锁住整个对象:当`synchronized`后面跟的是`this`或者类实例时,锁住的是整个对象,不允许其他线程同时访问对象的所有`synchronized`方法和代码块。 二、Lock接口 Lock接口提供了更灵活的锁控制,比`...

    lock-example:使用C#进行多线程锁定的示例

    类LockExample.Lib.Utilities.SomeUtility有两种方法。 一个是lock ,另一个没有。 public void PerformSomeOperationWithLock ( InputOutputValue inputOutputValues ) { lock ( this ) { // code here... } ...

    Kotlin中双冒号::使用方法

    Kotlin 中双冒号 :: 使用方法 Kotlin 中双冒号 :: 使用方法是一种特殊的语法结构,它可以将一个方法作为参数传递给另外一个方法。这种语法结构在实际开发中非常有用,本文将详细介绍 Kotlin 中双冒号 :: 使用方法的...

    解析使用C# lock同时访问共享数据

    最初的尝试使用`lock(this)`,但这是不合适的,因为每个实例的`this`引用是不同的,无法实现同步。正确的做法是使用一个所有线程共享的静态对象,例如`EmailInfo.syncRoot`: ```csharp class EmailInfo { public ...

    DistributedLock:使用Redis的分布式锁

    在这个例子中,`lock()`方法尝试使用`SETNX`获取锁,而`unlock()`方法在释放锁之前会检查是否确实拥有锁,防止误删其他实例的锁。注意,实际应用中还需要处理锁自动续期、超时未释放等问题,以防止死锁。 在测试...

    redislock-基于redis的分布式可重入锁

    1. **获取锁**:客户端尝试使用`SETNX`命令设置一个特定的键,如`lock:<resource>`,如果成功,说明获得了锁。同时,设置一个合理的过期时间,以防客户端异常退出后无法释放锁。 2. **可重入性**:为了实现可重入性...

    Hibernate.lock()方法中各种锁的区别.docx

    ### Hibernate.lock() 方法中各种锁的区别 #### 一、悲观锁与乐观锁概念解析 **悲观锁**(Pessimistic Lock)与**乐观锁**(Optimistic Lock)是数据库和对象关系映射(ORM)框架中两种重要的锁定机制,主要用于...

Global site tag (gtag.js) - Google Analytics