.NET中的lock

原创 2007年10月13日 19:43:00

lock 关键字可将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。此语句的形式如下:
lock(expression) statement_block
其中:
expression
指定要锁定的对象。expression 必须是引用类型。
通常,如果要保护实例变量,则 expression 为 this;如果要保护 static 变量(或者如果临界区出现在给定类的静态方法中),则 expression 为 typeOf (class)。
statement_block
临界区的语句。
备注
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入一个锁定代码,则它将在释放该对象前一直等待(块)。
8.12 lock 语句对 lock 进行了讨论。
示例 1
下例显示的是在 C# 中使用线程的简单示例。
// statements_lock.cs
using System;
using System.Threading;

class ThreadTest
{
   public void runme()
   {
      Console.WriteLine("runme called");
   }

   public static void Main()
   {
      ThreadTest b = new ThreadTest();
      Thread t = new Thread(new ThreadStart(b.runme));
      t.Start();
   }
}
输出
runme called
示例 2
下例使用线程和 lock。只要 lock 语句存在,语句块就是临界区并且 balance 永远不会是负数。
// statements_lock2.cs
using System;
using System.Threading;

class Account
{
   int balance;

   Random r = new Random();

   public Account(int initial)
   {
      balance = initial;
   }

   int Withdraw(int amount)
   {

      // This condition will never be true unless the lock statement
      // is commented out:
      if (balance < 0)
      {
         throw new Exception("Negative Balance");
      }

      // Comment out the next line to see the effect of leaving out
      // the lock keyword:
      lock (this)
      {
         if (balance >= amount)
         {
            Console.WriteLine("Balance before Withdrawal :  " + balance);
            Console.WriteLine("Amount to Withdraw        : -" + amount);
            balance = balance - amount;
            Console.WriteLine("Balance after Withdrawal  :  " + balance);
            return amount;
         }
         else
         {
            return 0; // transaction rejected
         }
      }
   }

   public void DoTransactions()
   {
      for (int i = 0; i < 100; i++)
      {
         Withdraw(r.Next(1, 100));
      }
   }
}

class Test
{
   public static void Main()
   {
      Thread[] threads = new Thread[10];
      Account acc = new Account (1000);
      for (int i = 0; i < 10; i++)
      {
         Thread t = new Thread(new ThreadStart(acc.DoTransactions));
         threads[i] = t;
      }
      for (int i = 0; i < 10; i++)
      {
         threads[i].Start();
      }
   }
}

我们先来看几个案例,看看lock是什么.
 1     public class ThreadTest
 2     {
 3         private int i = 0;
 4         public void Test()
 5         {
 6             Thread t1 = new Thread(Thread1);
 7             Thread t2 = new Thread(Thread2);
 8             t1.Start();
 9             t2.Start();
10         }
11         public void Thread1()
12         {
13             lock (this)
14             {
15                 Console.WriteLine(this.i);
16                 Thread.Sleep(1000);
17                 Console.WriteLine(this.i);
18             }
19         }
20         public void Thread2()
21         {
22             Thread.Sleep(500);
23             this.i = 1;
24             Console.WriteLine("Change the value in locking");
25         }
26     }
27     public class ThreadTest2
28     {
29         private int i = 0;
30         public void Test()
31         {
32             Thread t1 = new Thread(Thread1);
33             Thread t2 = new Thread(Thread2);
34             t1.Start();
35             t2.Start();
36         }
37         public void Thread1()
38         {
39             lock (this)
40             {
41                 Console.WriteLine(this.i);
42                 Thread.Sleep(1000);
43                 Console.WriteLine(this.i);
44             }
45         }
46         public void Thread2()
47         {
48             lock (this)
49             {
50                 Thread.Sleep(500);
51                 this.i = 1;
52                 Console.WriteLine("Can't change the value in locking");
53             }
54         }
55     }

      两段程序有什么区别吗?看看吧,ThreadTest2.Thread2()中多了一个lock(this)却产生了不同的结果

      本想在案例一中lock住this对象,让其他的线程不能操作,可是事情不是像我们想象的那样lock(this)是lock this的意思.this中的属性依然能够被别的线程改变.那我们lock住的是什么?是代码段,是lock后面大括号中代码段,这段代码让多个人执行不不被允许的.那返回头来在看lock(this),this是什么意思呢?可以说this知识这段代码域的标志,看看案例二中Thread2.Thread2就明白了,Thread2中的lock需要等到Thread1种lock释放后才开始运行,释放之前一直处于等待状态,这就是标志的表现.

      好吧,让我们来了解一下,lock这段代码是怎么运行的.lock语句根本使用的就是Monitor.Enter和Monitor.Exit,也就是说lock(this)时执行Monitor.Enter(this),大括号结束时执行Monitor.Exit(this).他的意义在于什么呢,对于任何一个对象来说,他在内存中的第一部分放置的是所有方法的地址,第二部分放着一个索引,他指向CLR中的SyncBlock Cache区域中的一个SyncBlock.什么意思呢?就是说,当你执行Monitor.Enter(Object)时,如果object的索引值为负数,就从SyncBlock Cache中选区一个SyncBlock,将其地址放在object的索引中。这样就完成了以object为标志的锁定,其他的线程想再次进行Monitor.Enter(object)操作,将获得object为正数的索引,然后就等待。直到索引变为负数,即线程使用Monitor.Exit(object)将索引变为负数。

       如果明白了Monitor.Enter的原理,lock当然不再话下.当然lock后括号里面的值不是说把整个对象锁住,而是对他的一个值进行了修改,使别的lock不能锁住他,这才是lock(object)的真面目.

       但在实际使用中Monitor还是不推荐,还是lock好的,Monitor需要加上很多try catch才能保证安全性,但lock却帮我们做了,而且lock看起来更优雅.

       在静态方法中如何使用lock呢,由于我们没有this可用,所以我们使用typeof(this)好了,Type也有相应的方法地址和索引,所以他也是可以来当作lock的标志的.

       但微软不提倡是用public的object或者typeof()或者字符串这样的标志就是因为,如果你的public object在其他的线程中被null并被垃圾收集了,将发生不可预期的错误.

C# Lock 解读

最近在研究.NET分布式缓存代码,正好涉及Lock,看了网上的文章,总结了一些Lock相关的知识,供大家一起学习参考。  一、Lock定义     lock 关键字可以用来确保代码块完成运行,而不...
  • vincent_zhanglb
  • vincent_zhanglb
  • 2012年01月01日 19:01
  • 14950

C# ASP.NET B/S模式下,采用lock语法 实现多用户并发产生不重复递增单号的一种解决方法技术参考

转载自:http://www.cnblogs.com/12go/archive/2011/12/24/2300204.html   往往我们在开发程序、调试程序时,无法模拟多用户同时操作的实际环境...
  • meizhiyun
  • meizhiyun
  • 2013年03月08日 10:41
  • 4189

C#多线程开发6:使用lock语句同步多个线程

在多个线程之间共享数据时,需要考虑线程同步问题,必须确保每次只有一个线程访问和改变共享数据。 C#中使用lock语句可以轻松地设置和解除锁定以期达到每次只有一个线程访问和改变共享数据的目的。 下面...
  • tiana0
  • tiana0
  • 2015年05月25日 18:10
  • 3658

深入理解Lock的底层实现原理

lock的实现完全是由java写的,和操作系统或者是JVM虚拟机没有任何关系。整体来看Lock主要是通过两个东西来实现的分别是CAS和ASQ(AbstractQueuedSynchronizer)。通...
  • liyantianmin
  • liyantianmin
  • 2017年01月22日 23:58
  • 1449

.NET LOCK使用方法

  • 2012年10月22日 18:37
  • 720KB
  • 下载

lock Mutex Monitor 之间的区别与详解, .net 多线程 同步异步操作,锁

Framework为我们提供了三个加锁的机制,分别是Monitor类、Lock关 键字和Mutex类。   总体而言,lock和monitor可以锁定对象,也可以锁定函数;而mutex一般用...
  • xwdpepsi
  • xwdpepsi
  • 2012年10月02日 11:20
  • 3285

asp.net c# lock 有关

lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断。这是通过在代码块运行期间为给定对象获取互斥锁来实现的。  有一个作为参数的对象,在该参数的后面还有一个一次只能由一个线程执行的代码块...
  • Joyhen
  • Joyhen
  • 2012年12月15日 14:23
  • 1139

.net lock的使用方法

源地址 http://blog.sina.com.cn/s/blog_69f048190100xu2l.html   lock就是把一段代码定义为临界区,所谓临界区就是同一时刻只能有一个线程来操作临界...
  • hebeijg
  • hebeijg
  • 2013年08月06日 11:25
  • 674

.NET中lock的使用方法及注意事项

lock就是把一段代码定义为临界区,所谓临界区就是同一时刻只能有一个线程来操作临界区的代码,当一个线程位于代码的临界区时,另一个线程不能进入临界区,如果试图进入临界区,则只能一直等待(即被阻止),直到...
  • ddxkjddx
  • ddxkjddx
  • 2012年02月20日 11:02
  • 552

Asp.net的条件和循环语句示例(If,Swich,While,For,Goto,foreach,Lock可直接运行)

#region =========================================================== \\ ★ 【判断语句】 Respons...
  • dxnn520
  • dxnn520
  • 2012年11月04日 05:55
  • 6512
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:.NET中的lock
举报原因:
原因补充:

(最多只允许输入30个字)