谈谈 Lock
上来先看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的更多相关文章
- C#中lock死锁实例教程
这篇文章主要介绍了C#中lock死锁的用法,对于共享资源的访问及C#程序设计的安全性而言,有着非常重要的意义!需要的朋友可以参考下 链接:http://www.jb51.net/article/543 ...
- 谈谈线程同步Lock和unLock
Lock可以使用Condition进行线程之间的调度,它有更好的灵活性,而且在一个对象里面可以有多个Condition(即对象监视器),则线程可以注册在不同的Condition,从而可以 有选择性的调 ...
- 谈谈如何使用Netty开发实现高性能的RPC服务器
RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...
- 从一个简单的Java单例示例谈谈并发
一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这么写 public class UnsafeLazyInitiallization { private static Un ...
- 从一个简单的Java单例示例谈谈并发 JMM JUC
原文: http://www.open-open.com/lib/view/open1462871898428.html 一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这 ...
- 《深入浅出 Java Concurrency》—锁紧机构(一)Lock与ReentrantLock
转会:http://www.blogjava.net/xylz/archive/2010/07/05/325274.html 前面的章节主要谈谈原子操作,至于与原子操作一些相关的问题或者说陷阱就放到最 ...
- 谈谈java的BlockingQueue
http://www.cnblogs.com/archy_yu/archive/2013/04/19/3018479.html 博客园 首页 新随笔 联系 管理 随笔- 92 文章- 0 评论- ...
- BAT美团滴滴java面试大纲(带答案版)之三:多线程Lock
继续面试大纲系列文章. 这是多线程的第二篇. 多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸芸众生:而滥用则会遭其反噬. 在多线程编程中要渡的第二个“劫”,则是Lock.在很多时候, ...
- BAT美团滴滴java面试大纲(带答案版)之四:多线程Lock
每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 这是多线程的第二篇. 多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸 ...
随机推荐
- 探究@property申明对象属性时copy与strong的区别
一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...
- Spring之旅
Java使得以模块化构建复杂应用系统成为可能,它为Applet而来,但为组件化而留. Spring是一个开源的框架,最早由Rod Johnson创建.Spring是为了解决企业级应用开发的复杂性而创建 ...
- jQuery学习之路(3)- 事件
▓▓▓▓▓▓ 大致介绍 jQuery增加了并扩展了基本的事件处理机制,不但提供了更加优雅的事件处理语法,而且极大地增强了事件处理能力 ▓▓▓▓▓▓ jQuery中的事件 ▓▓▓▓▓▓ 加载DOM 在j ...
- Node.js:Buffer浅谈
Javascript在客户端对于unicode编码的数据操作支持非常友好,但是对二进制数据的处理就不尽人意.Node.js为了能够处理二进制数据或非unicode编码的数据,便设计了Buffer类,该 ...
- [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?
你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...
- 就这么漂来漂去---一个毕业三个月的java程序员的裸辞风波
注:这并不是一篇技术文章,而是记录了我这几个月经历的入职,裸辞,找工作的心路历程,简单介绍一个博主的情况,我是16年毕业生,校招进了一家北京的公司,java开发,和很多年轻人一样,干了一段时间,我发现 ...
- 【用户交互】APP没有退出前台但改变系统属性如何实时更新UI?监听系统广播,让用户交互更舒心~
前日,一小伙伴问我一个问题,说它解决了半天都没解决这个问题,截图如下: 大概楼主理解如下: 如果在应用中有一个判断wifi的开关和一个当前音量大小的seekbar以及一个获取当前电量多少的按钮,想知道 ...
- Unity3D框架插件uFrame实践记录(二)
5.创建属性和命令 本小节主要内容包括: 在Element节点上创建属性数据 在Element节点上创建命令数据 5.1.在Element节点上创建属性数据 在这里,我们首先为Login节点中的属性( ...
- 图解CSS3制作圆环形进度条的实例教程
圆环形进度条制作的基本思想还是画出基本的弧线图形,然后CSS3中我们可以控制其旋转来串联基本图形,制造出部分消失的效果,下面就来带大家学习图解CSS3制作圆环形进度条的实例教程 首先,当有人说你能不能 ...
- closure
什么是闭包?百度的答案: 闭包是指可以包含自由(未绑定到特定对象)变量的代码块:这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)."闭包&quo ...