为什么要用lock 【readonly】object?为什么不要lock(this)?
一. 为什么要用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();
}
}
} //所有线程都可以同时访问的方法
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(); //在主线程中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的代码在同一时刻只能由一个线程访问
publicvoid LockMe(object o)
{
lock (locker)
{
while(deadlocked)
{
deadlocked = (bool)o;
Console.WriteLine("Foo: I am locked :(");
Thread.Sleep();
}
}
} //所有线程都可以同时访问的方法
publicvoid DoNotLockMe()
{
Console.WriteLine("I am not locked :)");
}
}
这次我们使用一个私有成员作为锁定变量(locker),在LockMe中仅仅锁定这个私有locker,而不是整个对象。这时候重新运行程序,可以看到虽然t1出现了死锁,DoNotLockMe()仍然可以由主线程访问。LockMe()依然不能访问,原因是其中锁定的locker还没有被t1释放。
关键点:
1.lock(this)的缺点就是在一个线程锁定某对象之后导致整个对象无法被其他线程访问。
2.锁定的不仅仅是lock段里的代码,锁本身也是线程安全的。
3.我们应该使用不影响其他操作的私有对象作为locker。
4.在使用lock的时候,被lock的对象(locker)一定要是引用类型的,如果是值类型,将导致每次lock的时候都会将该对象装箱为一个新的引用对象(事实上如果使用值类型,C#编译器(3.5.30729.1)在编译时就会给出一个错误)。
备注:
对于Monitor,发现它的静态方法Enter(object obj)有一个异常类型ArgumentNullException,执行lock(null对象 )处,抛出未处理的异常:System.ArgumentNullException: 值不能为空!
在代码段中修改锁定对象,会出现 blance<0的情况,并会抛出异常。
private static readonly object obj = new object();
为什么要设置成只读的呢?这是因为如果在lock代码段中改变obj的值,其它线程就畅通无阻了。因为互斥锁的对象变了,object.ReferenceEquals必然返回false。所以把上面的修改成private static readonly。
参考链接:https://www.cnblogs.com/chenheng0056/p/3444304.html
为什么要用lock 【readonly】object?为什么不要lock(this)?的更多相关文章
- [问题解决] initAndListen: 10309 Unable to create/open lock file: /data/db/mongod.lock
错误: 在linux下开启mongoDB的 $ >bin: ./mongod 时报错:initAndListen: 10309 Unable to create/open lock file: ...
- E:Could not get lock /var/lib/apt/lists/lock - open (11: Resource temporarily unavailable)
出现这个问题的原因可能是有另外一个程序正在运行,导致资源被锁不可用.而导致资源被锁的原因,可能是上次安装时没正常完成,而导致出现此状况. 解决方法:输入以下命令 sudo rm /var/cache/ ...
- Synchronized和Lock, 以及自旋锁 Spin Lock, Ticket Spin Lock, MCS Spin Lock, CLH Spin Lock
Synchronized和Lock synchronized是一个关键字, Lock是一个接口, 对应有多种实现. 使用synchronized进行同步和使用Lock进行同步的区别 使用synchro ...
- 解决 E: Could not get lock /var/lib/apt/lists/lock
参考:Unable to lock the administration directory (/var/lib/dpkg/) is another process using it? 在更换软件源时 ...
- Could not get lock /var/lib/apt/lists/lock
执行: apt-get update 出现 Could not get lock /var/lib/apt/lists/lock 解决办法: 查询与apt相关的进程 ps -e | grep apt ...
- 解决Could not get lock /var/cache/apt/archives/lock
在ubuntu apt-get upgrade的时候,遇到: E: Could not get lock /var/cache/ apt/archives/lock - open (11 Resour ...
- Ubuntu遇到apt-get update报错:"E: Could not get lock /var/lib/apt/lists/lock"
sudo apt-get update报错:"E: Could not get lock /var/lib/apt/lists/lock" 出现此问题的原因可能是有另外一个程序在运 ...
- ubuntu E: Could not get lock /var/lib/apt/lists/lock 异常信息
转载:https://www.cnblogs.com/qq952693358/p/6537846.html 在更换软件源时遇到了如下问题: sudo apt-get update E: Could n ...
- Could not open lock file/var/lib/dpkg/lock的解决
Could not open lock file/var/lib/dpkg/lock的解决 在ubuntu系统中利用apt-get install something的时候,有时候会出现无法获得锁的权 ...
- sudo apt-get update:Could not get lock /var/lib/apt/lists/lock解决办法
原文: http://blog.chinaunix.net/uid-26932153-id-3193335.html 今天更新时候出现了点小问题,一开始更新到一半,我嫌速度慢,就取消掉了. 更新了so ...
随机推荐
- SQL注入之PHP-MySQL实现手工注入-字符型
SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎 ...
- PHP eval函数
代码: eval("echo'hello world';"); 上边代码等同于下边的代码: echo"hello world"; 在浏览器中都输出:hello ...
- javaweb项目中的过滤器的使用
翻阅博客园的的时候,看到两篇关于javaweb过滤器的帖子写的很好,这里备忘一下: 过滤器基础:http://www.cnblogs.com/xdp-gacl/p/3948353.html 获取器案例 ...
- centos7 安装cmake
安装cmake之前,记得升级gcc,请参考centos7 升级GCC版本到7.3.0 #shell 太简单,懒得解释 wget https://cmake.org/files/v3.11/cmake- ...
- [LeetCode] Z字型变换
题目内容: 将字符串 "PAYPALISHIRING" 以Z字形排列成给定的行数: P A H N A P L S I I G Y I R 之后从左往右,逐行读取字符:" ...
- C++类和对象(一)&&实现offsetof宏&&this指针
一.目录 1.对象的相关知识 2.类的定义 3.类的实例化 4.类对象模型 5.模拟实现offsetof宏 6.this指针 二.正文 1.对象的相关知识 C语言是面向过程的,关注的是过程,分析求解问 ...
- Docker三剑客之常用命令
一.docker-machine 命令 说明 docker-machine create 创建一个 Docker 主机(常用-d virtualbox) docker-machine ls 查看所有的 ...
- 在Storm的Toplogy中设置多数据源Spout
上代码:主要看main方法中的设置. 如下代码是一般情况下的设置方法...Trident中设置多数据源看对应的博客总结 /** * 指定多个数据源 * 数字累加求和 * 先添加storm依赖 */ ...
- 8皇后问题(c++/python实现)
问题描述:在8*8的国际象棋盘上摆放8个皇后,使其不能互相攻击,即任何两个皇后都不能处于同一行.同一列或者同一斜线上,问有多少种摆法. 算法分析: 利用3个数组分表来标记冲突,数组a.b.c. a数组 ...
- Android的几种弹出框
项目效果图: 新建一个项目,结构图如下所示: activity_main.xml: <?xml version="1.0" encoding="utf-8" ...