C# 使用lock关键字lock不同的对象

摘要:
c#lock关键字的本质是调用Monitor.Enter(objectobj)并且在finally的时候调用Monitor.Exit(obj)在obj是不同数据类型的时候会出现不同的情况1.锁定类型例如lock(typeof(int))lock(typeof(ClassA))//CalssA是一个类的定义备注:前者作用范围跨AppDomain不跨Process,后者不跨AppDomain(默认设置

c# lock关键字的本质

是调用Monitor.Enter(object obj)并且在finally的时候调用Monitor.Exit(obj)

在obj是不同数据类型的时候会出现不同的情况

1.锁定类型 例如lock(typeof(int)) lock(typeof(ClassA)) // CalssA 是一个类的定义

备注:前者作用范围跨AppDomain 不跨Process, 后者不跨AppDomain(默认设置)

使用范围:绝不推荐使用

2.锁定字符串 例如lock("abc") 和lock(s)//s是一个字符串的实例变量

备注:当字符串已经驻留在内存的时候 这个lock是有效的, 如果字符串未驻留在内存那么这个lock就失效了,该lock是跨Appdomain不跨Process

使用范围: 一般不推荐使用

以下代码显示了非驻留字符串导致的无法lock的问题,请在实际应用中避免lock(a+b)即使他们的值一样 (vs2008 Debug)

代码
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading;
namespaceConsoleApplication1
{
classProgram
{
staticvoidMain(string[] args)
{
strings1 ="a";
strings2 ="bc";
ThreadPool.QueueUserWorkItem(p
=>
{
Thread.Sleep(
3000); Console.WriteLine("Thread2 Begin Test");
lock(s1 +s2)
{
Console.WriteLine(
"Thread2 Begin Lock");
Thread.Sleep(
1000);
Console.WriteLine(
"Thread2 End Lock");
}
});
Console.WriteLine(
"Thread1 Begin Test");
lock(s1 +s2)
{
Console.WriteLine(
"Thread1 Begin Lock");
Thread.Sleep(
10000);
Console.WriteLine(
"Thread1 End Lock");
}
}
}
}

3.所有继承于System.MarshalByRefObject 的对象 ,例如Remoting Service之类的

备注:锁定的是代理对象,在远端的对象并没有被锁定(byValue 和byRef 两种类型传数据也有影响)

使用范围:不推荐

4.值类型, 由于众所周知的装箱的问题...实际上锁定根本不生效

使用范围:不推荐

5. 应用[MethodImpl(MethodImplOptions.Synchronized)]标记的类

实例方法锁定的是this lock(this)

静态方法锁定的是typeof(ClassName) lock(typeof(ClassName)) //ClassName是你当前的类名

使用范围:不推荐, 调用静态方法将导致锁定类型, 实例方法之间也相互影响锁定关系

6.lock(this)

很容易误用,例如在web page上调用 lock(this)....由于asp.net会为每次httpRequest , new一个类的实例...所以lock(this)在这里一点作用都没有

在其他的情况下:lock(this)锁定了本身,那么但其他外部对象试图使用这个类的时候会有困扰

如果你的类是public给其他人用的,那么最好不要lock(this)

请参考以下代码(不推荐使用)

代码
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading;
namespaceConsoleApplication1
{
publicclassClassA
{
publicvoidTest()
{
lock(this)
{
Console.WriteLine(
"Test Begin Lock");
Thread.Sleep(
10000);
Console.WriteLine(
"Test End Lock");
}
}
}
classProgram
{
staticvoidMain(string[] args)
{
ClassA classA
=newClassA();
ThreadPool.QueueUserWorkItem(p
=>
{
Thread.Sleep(
3000); Console.WriteLine("Thread2 Begin Test");
lock(classA)
{
Console.WriteLine(
"Thread2 Begin Lock");
Thread.Sleep(
1000);
Console.WriteLine(
"Thread2 End Lock");
}
});
classA.Test();
Console.ReadLine();
}
}
}

7. lock(null) 必然抛出一个异常

8.推荐使用以下方法lock

private static object asyncLock=new object();

lock(asyncLock)

使用 private object asyncLock=new object(); 也是ok的,但是请注意避免之前提到的WebPage每次new一个类导致lock失效的问题

影响范围不跨AppDomain

PS1:关于跨不跨AppDomain的问题,其实用处不大,大部分应用程序都只是创建一个DefaultDomain

PS2:可以将一些Assembly设置为跨AppDomain的,以减少内存浪费和提高性能, 例如string和一些基本类型都是这样实现的

PS3:本人水平有限,如果错漏还请大家帮忙...

免责声明:文章转载自《C# 使用lock关键字lock不同的对象》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇关于改windows密码后,SQL服务管理器自动停止的问题Linux--CentOS 安装 Docker 教程下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

ubuntu网卡配置

网卡配置文件采用YAML格式,必须以/etc/netplan/XXX.yaml文件命名方式存放可以每个网卡对应一个单独的配置文件,也可以将所有网卡都放在一个配置文件里自动获取IProot@ubuntu1804:~#cat/etc/netplan/01-netcfg.yaml#Thisfiledescribesthenetworkinterfacesavail...

k8s集群上删除pod及service

删除k8s集群中的pod:找到pod的名称空间,并根据名称空间删除pod1。首先删除pod2,然后删除相应的部署。否则,删除pod是无用的。您还将看到pod,因为deployment.yaml文件中定义的副本数如下:delete the pod[root@test2~]#kubectlgetpod-njenkinsNAMEREADYSTATUSRESTART...

TensorRT在ubuntu18.04的安装

安装TensorRT前需要安装Cuda和cudnn,安装步骤可以参考ubuntu安装cuda和cudnn。...

Windows 远程桌面连接ubuntu及xrdp的一些小问题(远程桌面闪退、连接失败、tab补全功能,无菜单栏,error

想要修改,在windowsmanager中,keyboard里将用到Super+Tab的快捷键clear掉即可。解决:通过设置sesman.in文件内的参数解决:cat/etc/xrdp/sesman.inivi/etc/xrdp/sesman.ini可以修改会话设置:将最大会话限制该大MaxSessions=50;将KillDisconnected=1;则...

oracle instantclient_11_2插件安装

1.安装plsql2.instantclient_11_2下载并解压缩到目录D:DevToolsinstantclient_11_23.打开plsql并单击“取消”4.选择“工具”-˃“首选项”-˃“连接”-˃填写oracle主目录D:DevToolsinstantclient_12_2.填写OCI库D:Dev工具sinstantcient_11_ 2oci...

Android 9.0 系统启动流程

1、 启动过程概述II、Android启动分析III、init进程启动分析IV、init启动脚本分析V、init进程分析VI、init脚本执行VII、init进程守护程序VIII、initrc脚本启动Zygote IX、启动分析摘要I、启动过程概述Android启动过程与Linux启动类似,并将首先在系统中查找init.rc文件(大多数文件存储在/syste...