上来先看MSDN关于lock的叙述:

lock  关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。  下面的示例包含一个 lock 语句。

lock  关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。  如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

线程处理(C# 和 Visual Basic)  这节讨论了线程处理。

lock  关键字在块的开始处调用 Enter,而在块的结尾处调用 Exit。  ThreadInterruptedException  引发,如果 Interrupt 中断等待输入 lock 语句的线程。

通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。  常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:

• 如果实例可以被公共访问,将出现 lock (this) 问题。

• 如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。

• 由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock("myLock") 问题。

最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。

在 lock 语句的正文不能使用 等待 关键字。

通读上面叙述后,再来几个事例看看:

例一:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace NB.Demo
{
class Program
{
static void Main(string[] args)
{
Test t = new Test();
Thread[] threads = new Thread[];
for (int i = ; i < threads.Length; i++)
{ threads[i] = new Thread(() =>
{
t.Print();
}); threads[i].Name = "thread" + i; } for (int i = ; i < threads.Length; i++)
{
threads[i].Start();
} Console.Read();
}
}
class MyLock
{
public int Id { get; set; }
} class Test
{
public void Print()
{
MyLock myLock = new MyLock();
lock (myLock)
{
for (int i = ; i < ; i++)
{
Console.WriteLine("\t" + Thread.CurrentThread.Name.ToString() + "\t" + i.ToString() + " ");
}
}
}
}
}

输出结果: 线程出现了争抢,这不是我们想要的结果,我们预期是每次只有一个线程去执行Print方法。

例二:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace NB.Demo
{
class Program
{
static void Main(string[] args)
{
Test t = new Test();
Test t0 = new Test();
Thread[] threads = new Thread[];
for (int i = ; i < threads.Length; i++)
{ threads[i] = new Thread(() =>
{
t.Print();
t0.Print();
}); threads[i].Name = "thread" + i; } for (int i = ; i < threads.Length; i++)
{
threads[i].Start();
} Console.Read();
}
}
class MyLock
{
public int Id { get; set; }
} class Test
{
public void Print()
{
lock (this)
{ for (int i = ; i < ; i++)
{
Console.WriteLine("\t" + Thread.CurrentThread.Name.ToString() + "\t" + i.ToString() + " ");
}
}
}
}
}

输出结果: 同样线程出现了争抢,这不是我们想要的结果。

例三:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace NB.Demo
{
class Program
{
static void Main(string[] args)
{
Test t = new Test(); Thread[] threads = new Thread[];
for (int i = ; i < threads.Length; i++)
{ threads[i] = new Thread(() =>
{
t.Print();
}); threads[i].Name = "thread" + i; } for (int i = ; i < threads.Length; i++)
{
threads[i].Start();
} Console.Read();
}
}
class MyLock
{
public int Id { get; set; }
} class Test
{
MyLock myobj = new MyLock();
public void Print()
{
lock (myobj)
{ for (int i = ; i < ; i++)
{
Console.WriteLine("\t" + Thread.CurrentThread.Name.ToString() + "\t" + i.ToString() + " ");
}
}
}
}
}

例四:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace NB.Demo
{
class Program
{
static void Main(string[] args)
{
Test t = new Test(); Thread[] threads = new Thread[];
for (int i = ; i < threads.Length; i++)
{ threads[i] = new Thread(() =>
{
t.Print();
}); threads[i].Name = "thread" + i; } for (int i = ; i < threads.Length; i++)
{
threads[i].Start();
} Console.Read();
}
}
class MyLock
{
public int Id { get; set; }
} class Test
{
private static object obj = new object();
public void Print()
{
lock (obj)
{ for (int i = ; i < ; i++)
{
Console.WriteLine("\t" + Thread.CurrentThread.Name.ToString() + "\t" + i.ToString() + " ");
}
}
}
}
}

例五:其他情况 如 Lock(type), Lock("string"),Lock("this")等

总结:

引用类型对象除实例字段的开销外,还有两个字段的开销:类型指针和同步块索引(SyncBlockIndex)。 在.net CLR世界,lock实际上是Moniter的包装。CLR初始化的时候,CLR会初始化一个SyncBlock的数组,当一个线程到达Monitor.Enter方法时,该线程会检查该方法接受的参数的同步块索引,默认情况下对象的同步块索引是一个默认值,那么表明该对象并没有一个关联的同步块,CLR就会在全局的SyncBlock数组里找到一个空闲的项,然后将数组的索引赋值给该对象的同步块索引,SyncBlock的内容和CRITICAL_SECTION的内容很相似,当Monitor.Enter执行时,它会设置SyncBlock里的内容,标识出已经有一个线程占用了,当另外一个线程进入时,它就会检查SyncBlock的内容,发现已经有一个线程占用了,该线程就会等待,当Monitor.Exit执行时,占用的线程就会释放SyncBlock,其他的线程可以进入操作了。

针对例一,锁定的对象是作为一个局部变量,每个线程进入的时候,锁定的对象都会不一样,它的SyncBlock每一次都是重新分配的,这个根本谈不上什么锁定不锁定。

针对例二,锁定的对象是Test类事例this,Test t和Test t0所代表的this都会不一样,它的SyncBlock就不一样,所以这种Lock也是无效的。

针对例五的那些其他情况:

一般说来应该没有什么事情,但这些操作却是很危险的。

typeof(..)得到的是..类的Type对象,所有..实例的Type都是同一个,Type对象也是一个对象,它也有自己的SyncBlock,Singleton的Type对象的SyncBlock在程序中只会有一份,为什么说这种做法是危险的呢?如果在该程序中,其他毫不相干的地方我们也使用了lock(typeof(..)),虽然它和这里的锁定毫无关系,但是只要一个地方锁定了,各个地方的线程都会在等待。

string也是应用类型,从语法上来说是没有错的。但是锁定字符串尤其危险,因为字符串被公共语言运行库 (CLR)“暂留”。 这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。

针对例三,本试验是没问题,但这种方式是不是有点不好的地方,留给各位思考。

谈谈 Lock的更多相关文章

  1. C#中lock死锁实例教程

    这篇文章主要介绍了C#中lock死锁的用法,对于共享资源的访问及C#程序设计的安全性而言,有着非常重要的意义!需要的朋友可以参考下 链接:http://www.jb51.net/article/543 ...

  2. 谈谈线程同步Lock和unLock

    Lock可以使用Condition进行线程之间的调度,它有更好的灵活性,而且在一个对象里面可以有多个Condition(即对象监视器),则线程可以注册在不同的Condition,从而可以 有选择性的调 ...

  3. 谈谈如何使用Netty开发实现高性能的RPC服务器

    RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...

  4. 从一个简单的Java单例示例谈谈并发

    一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这么写 public class UnsafeLazyInitiallization { private static Un ...

  5. 从一个简单的Java单例示例谈谈并发 JMM JUC

    原文: http://www.open-open.com/lib/view/open1462871898428.html 一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这 ...

  6. 《深入浅出 Java Concurrency》—锁紧机构(一)Lock与ReentrantLock

    转会:http://www.blogjava.net/xylz/archive/2010/07/05/325274.html 前面的章节主要谈谈原子操作,至于与原子操作一些相关的问题或者说陷阱就放到最 ...

  7. 谈谈java的BlockingQueue

    http://www.cnblogs.com/archy_yu/archive/2013/04/19/3018479.html 博客园 首页 新随笔 联系 管理 随笔- 92  文章- 0  评论- ...

  8. BAT美团滴滴java面试大纲(带答案版)之三:多线程Lock

    继续面试大纲系列文章. 这是多线程的第二篇. 多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸芸众生:而滥用则会遭其反噬. 在多线程编程中要渡的第二个“劫”,则是Lock.在很多时候, ...

  9. BAT美团滴滴java面试大纲(带答案版)之四:多线程Lock

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 这是多线程的第二篇. 多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸 ...

随机推荐

  1. Angular2入门系列教程2-项目初体验-编写自己的第一个组件

    上一篇 使用Angular-cli搭建Angular2开发环境 Angular2采用组件的编写模式,或者说,Angular2必须使用组件编写,没有组件,你甚至不能将Angular2项目启动起来 紧接着 ...

  2. 关于 Chrome 浏览器中 onresize 事件的 Bug

    我在写插件时用到了 onresize 事件,在反复地测试后发现该事件在 Chrome 及 Opera(内核基本与 Chrome 相同,以下统称 Chrome)浏览器打开时就会执行,这种情况也许不能算作 ...

  3. 支持 .NET Core 的 Memcached 客户端 EnyimMemcachedCore

    1. 介绍 EnyimMemcachedCore 是一个支持 .NET Core 的 Memcached 客户端,是从 EnyimMemcached 迁移至 .NET Core的,源代码托管在 Git ...

  4. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  5. 23种设计模式--观察者模式-Observer Pattern

    一.观察者模式的介绍      观察者模式从字面的意思上理解,肯定有两个对象一个是观察者,另外一个是被观察者,观察者模式就是当被观察者发生改变得时候发送通知给观察者,当然这个观察者可以是多个对象,在项 ...

  6. iOS逆向工程之KeyChain与Snoop-it

    今天博客的主题是Keychain, 在本篇博客中会通过一个登陆的Demo将用户名密码存入到KeyChain中,并且查看一下KeyChain中存的是什么东西,把这些内容给导出来.当然本篇博客的重点不是如 ...

  7. 更愉快的书写CSS

    我在写CSS的时候经常会碰到些麻烦事儿: 1)看上去蛮简单的排版却写了很久 2)代码写的越来越散,总是这里补一句,那里补一句,没有条理性 3)margin.padding.font-size等属性在不 ...

  8. 微信小程序(微信应用号)组件讲解

    这篇文章主要讲解微信小程序的组件. 首先,讲解新建项目.现在有句话:招聘三天以上微信小程序开发,这个估计只能去挖微信的工程师了.技术新,既然讲解,那我们就从开始建项目讲解. 打开微信web开发者工具, ...

  9. bzoj1723--前缀和(水题)

    题目大意: 你难以想象贝茜看到一只妖精在牧场出现时是多么的惊讶.她不是傻瓜,立即猛扑过去,用她那灵活的牛蹄抓住了那只妖精.     "你可以许一个愿望,傻大个儿!"妖精说.     ...

  10. MFC中成员变量的声明顺序与析构顺序

    第一次用博客,第一篇随笔,就写今天遇到的一个问题吧. 在VS2008的MFC对话框程序,窗口成员变量的声明顺序与其析构顺序相反,即,先声明的变量后析构,后声明的变量先析构.未在其他模式下测试. cla ...