why?

  1. 当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待。
  2. 但当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进行读写的时候,
  3. 我们要使该资源在同一时刻只能被一个线程操作,以确保每个操作都是有效即时的,也即保证其操作的原子性。
  4. lockC#中最常用的同步方式,格式为lock(objectA){codeB} 。
  5. lock (objectA) { codeB}
  6. 看似简单,实际上有三个意思,这对于适当地使用它至关重要:
  7. 1.objectAlock了吗?没有则由我来lock,否则一直等待,直至objectA被释放。
  8. 2.lock以后在执行codeB的期间其他线程不能调用codeB,也不能使用objectA
  9. 3.执行完codeB之后释放objectA,并且codeB可以被其他线程访问。

https://www.cnblogs.com/apsnet/archive/2012/07/08/2581475.html

  1. 即为了保证资源的一致性

when?

  1. 需要该资源在同一时刻只能被一个线程操作

how?

  1. 通过加锁来确保在操作完成之前不会被第二个资源进行访问

场景一:

  1. 存在生产与售出方法
  2. 两个方法同时操作库存

code:

  1. // 生产数量
  2. public int MakeCount { get; set; }
  3. // 售出数量
  4. public int SellCount { get; set; }
  5. //库存
  6. private int Products { get; set; }
  7. //产品制造
  8. public void Make(int num)
  9. {
  10. Products += num;
  11. MakeCount += num;
  12. Console.WriteLine($"生产了{num}个{ProductName},当前产品总数为:{Products}");
  13. }
  14. //产品售出
  15. public void Sell(int num)
  16. {
  17. if (Products < num)
  18. {
  19. Console.WriteLine($"库存不足,当前库存为:{Products}");
  20. return;
  21. }
  22. Products -= num;
  23. SellCount += num;
  24. Console.WriteLine($"售出了{num}个{ProductName},当前产品总数为:{Products}");
  25. }

result:

  1. 总生产数量: 11,总售出数量: 8,当前库存: 3,实际库存: 3
  2. 总生产数量: 31,总售出数量: 29,当前库存: 1,实际库存: 2
  3. 总生产数量: 51,总售出数量: 47,当前库存: 1,实际库存: 4
  4. 总生产数量: 73,总售出数量: 67,当前库存: 3,实际库存: 6
  5. 总生产数量: 93,总售出数量: 71,当前库存: 19,实际库存: 22
  6. 总生产数量: 97,总售出数量: 71,当前库存: 23,实际库存: 26

解决方法: 在操作数据时加锁,保证在同一时间仅有一个线程操作此数据

  1. private int _products;
  2. public int Products
  3. {
  4. get
  5. {
  6. return this._products;
  7. }
  8. set
  9. {
  10. lock (this)
  11. this._products = value;
  12. }
  13. }

note1: 单方法操作,不会导致数据异常

note2: 当执行时间越短,触发数据异常机遇越小

lock是如何执行的?

lock <==> Monitor

  1. lock (this)
  2. {
  3. _products = value;
  4. }
  5. //等价于:
  6. bool lockTaken = false;
  7. try
  8. {
  9. Monitor.Enter(this, ref lockTaken);
  10. _products = value;
  11. }
  12. finally
  13. {
  14. if (lockTaken) Monitor.Exit(this);
  15. }

https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.monitor?view=netframework-4.8

什么是Monitor?/Monitord有什么作用?

提供同步访问对象的机制。

Monitor的使用

code:

  1. //库存
  2. private int goods { get; set; }
  3. //生产量
  4. private int make { get; set; }
  5. //销售量
  6. private int sell { get; set; }
  7. public void Make()
  8. {
  9. if (Monitor.TryEnter(_lock, TimeSpan.FromMilliseconds(1000)))
  10. {
  11. try
  12. {
  13. goods++;
  14. make++;
  15. Console.WriteLine($"制造了一个产品,当前产品数量:{goods}");
  16. ////System.Threading.SynchronizationLockException:“Object synchronization method was called from an unsynchronized block of code.”
  17. //为避免生产过量,生产完后会提醒销售售出
  18. Monitor.Pulse(_lock);
  19. }
  20. finally
  21. {
  22. Monitor.Exit(_lock);
  23. }
  24. }
  25. else
  26. {
  27. Console.WriteLine("生成失败");
  28. }
  29. }
  30. public void Sell()
  31. {
  32. if (Monitor.TryEnter(_lock, TimeSpan.FromMilliseconds(1000)))
  33. {
  34. while (goods <= 0) //库存不足
  35. {
  36. //System.Threading.SynchronizationLockException:“Object synchronization method was called from an unsynchronized block of code.”
  37. //同步方法不能在非同方方法中调用
  38. if (!Monitor.Wait(_lock, TimeSpan.FromMilliseconds(1000))) //等待生成
  39. {
  40. Console.WriteLine("库存不足!");
  41. return;
  42. }
  43. }
  44. sell++;
  45. goods--;
  46. Console.WriteLine($"售出了一个产品,当前库存:{goods}");
  47. }
  48. else
  49. {
  50. Console.WriteLine($"购买失败");
  51. }
  52. }
  53. public void Show()
  54. {
  55. Console.WriteLine($"当前库存:{goods},生产量:{make},销售量:{sell},实际库存:{sell - make}");
  56. if (make - sell != goods) throw new Exception("销售异常!");
  57. }

note

  1. 同步索引块是.NET中解决对象同步问题的基本机制
  2. 这个对象肯定要是引用类型,值类型可不可呢?值类型可以装箱啊!你觉得可不可以?但也不要用值类型,因为值类型多次装箱后的对象是不同的,会导致无法锁定;
  3. 不要锁定this,尽量使用一个没有意义的Object对象来锁;
  4. 不要锁定一个类型对象,因类型对象是全局的;
  5. 不要锁定一个字符串,因为字符串可能被驻留,不同字符对象可能指向同一个字符串;
  6. 不要使用[System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.Synchronized)],这个可以使用在方法上面,保证方法同一时刻只能被一个线程调用。她实质上是使用lock的,如果是实例方法,会锁定this,如果是静态方法,则会锁定类型对象;

confirm

通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。

常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:

  1. 如果实例可以被公共访问,将出现 lock (this) 问题。
  2. 如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
  3. 由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。

ext

https://www.cnblogs.com/anding/p/5301754.html

https://www.cnblogs.com/carsonzhu/p/7446953.html


author:monster

since:5/7/2019 2:02:24 PM

direction:lock

lock学习篇(上)的更多相关文章

  1. c++学习笔记之封装篇(上)

    title: c++学习笔记之封装篇(上) date: 2017-03-12 18:59:01 tags: [c++,c,封装,类] categories: [学习,程序员,c/c++] --- 一. ...

  2. 6-C++远征之封装篇[上]-学习笔记

    C++远征之封装篇(上) 课程简介 类(抽象概念),对象(真实具体) 配角: 数据成员和成员函数(构成了精彩而完整的类) 构造函数 & 析构函数(描述了对象的生生死死) 对象复制和对象赋值 ( ...

  3. js学习篇1--数组

    javascript的数组可以包含各种类型的数据. 1. 数组的长度 ,直接用 length 属性; var arr=[1,2,3]; arr.length; js中,直接给数组的length赋值是会 ...

  4. Tomcat集群配置学习篇-----分布式应用

    Tomcat集群配置学习篇-----分布式应用 现目前基于javaWeb开发的应用系统已经比比皆是,尤其是电子商务网站,要想网站发展壮大,那么必然就得能够承受住庞大的网站访问量:大家知道如果服务器访问 ...

  5. (转载)OC学习篇之---概述

    前言 终于开启了OC的学习篇了,之前由于工作上的事,学习就一直搁浅了,不过最近由于各种原因,感觉必须要开启iOS的开发旅程了,不然就老了.因为之前一直是做Android的,所以学习iOS来就没那么费劲 ...

  6. zookeeper学习(上)

    zookeeper学习(上) 在前面的文章里我多次提到zookeeper对于分布式系统开发的重要性,因此对zookeeper的学习是非常必要的.本篇博文主要是讲解zookeeper的安装和zookee ...

  7. 鸟哥Linux私房菜基础学习篇学习笔记3

    鸟哥Linux私房菜基础学习篇学习笔记3 第十二章 正则表达式与文件格式化处理: 正则表达式(Regular Expression) 是通过一些特殊字符的排列,用以查找.删除.替换一行或多行文字字符: ...

  8. 鸟哥Linux私房菜基础学习篇学习笔记2

    鸟哥Linux私房菜基础学习篇学习笔记2 第九章 文件与文件系统的压缩打包: Linux下的扩展名没有什么特殊的意义,仅为了方便记忆. 压缩文件的扩展名一般为: *.tar, *.tar.gz, *. ...

  9. 鸟哥Linux私房菜基础学习篇学习笔记1

    鸟哥Linux私房菜基础学习篇学习笔记1 第三章 主导分区(MBR),当系统在开机的时候会主动去读取这个区块的内容,必须对硬盘进行分区,这样硬盘才能被有效地使用. 所谓的分区只是针对64Bytes的分 ...

随机推荐

  1. Swift-使用transform 实现重复平移动画

    摘要 要实现一组重复的动画,本质上就是找到动画开始点.结束点.在动画结束的时候,触发开始点,持续这样的动作. 这里面要梳理的逻辑就是1.触发开始点和2.监听动画结束点.这两个逻辑是实现重复动画的基础. ...

  2. ACM金牌选手讲解LeetCode算法《栈和队列的高级应用》

    大家好,我是编程熊,双非逆袭选手,字节跳动.旷视科技前员工,ACM金牌,保研985,<ACM金牌选手讲解LeetCode算法系列>作者. 上一篇文章讲解了<线性表>中的数组.链 ...

  3. 高性能内存图数据库RedisGraph(二)

    这篇文章主要介绍用一下RedisGraph的历史和现状. 2018年5月,Redis Labs发布了RedisGraph的预览/测试版.6个月后,在Redis Labs和开源社区的开发者们的共同努力下 ...

  4. 使用jquery的on方法注册事件遇到的坑

    1,使用on注册事件 $(selector).on(event,childSelector,data,function) 2,$(selector)中的selector可以是document,那么意味 ...

  5. 8Java设计模式(持续更新)

    1.单例模式(Singleton pattern): 单例模式的实现方式是,一个类能返回对象的一个引用(永远是同一个)和一个获得该唯一实例的方法(必须是静态方法). 饿汉式: public class ...

  6. PAT甲级:1066 Root of AVL Tree (25分)

    PAT甲级:1066 Root of AVL Tree (25分) 题干 An AVL tree is a self-balancing binary search tree. In an AVL t ...

  7. POJ1723,1050,HDU4864题解(贪心)

    POJ1723 Soldiers 思维题. 考虑y坐标,简单的货舱选址问题,选择中位数即可. 再考虑x坐标,由于直接研究布置方法非常困难,可以倒着想:不管如何移动,最后的坐标总是相邻的,且根据贪心的思 ...

  8. Python中调用Java程序包

    <原创不易,转载请标明出处:https://www.cnblogs.com/bandaobudaoweng/p/10785766.html> 开发Python程序,需求中需要用到Java代 ...

  9. 【LeetCode】面试题62. 圆圈中最后剩下的数字

    题目:面试题62. 圆圈中最后剩下的数字 这题很有意思,也很巧妙,故记录下来. 官方题解思路,是约瑟夫环的数学解法: 我们将上述问题建模为函数 f(n, m),该函数的返回值为最终留下的元素的序号. ...

  10. 利用postman进行api接口开发

    场景: api接口开发时,经常使用一些工具来帮助设计开发.Yapi主要是在设计阶段进行api接口设计,统一前后端参数请求和返回体:swagger主要在开发阶段,用来显示实际上后端开发进度和接口情况:p ...