摘要

今天在园子里面有园友反馈关于[C#基础]说说lock到底锁谁?文章中lock(this)的问题。后来针对文章中的例子,仔细想了一下,确实不准确,才有了这篇文章的补充,已经对文章中的demo进行修改。

lock(this)

一个例子

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7.  
  8. namespace LockTest
  9. {
  10. class Program
  11. {
  12. static void Main(string[] args)
  13. {
  14. TestLock testlock = new TestLock();
  15. Thread th = new Thread(() =>
  16. {
  17. //模拟死锁:造成死锁,使lock无法释放,在i=5时,跳出死循环,释放lock
  18. testlock.DoWorkWithLock();
  19. });
  20. th.Start();
  21. Thread.Sleep();
  22. Thread th2 = new Thread(() =>
  23. {
  24. //这个地方你可能会有疑惑,但存在这种情况,比如你封装的dll,对其它开发人员不是可见的
  25. //开发人员很有可能在他的逻辑中,加上一个lock保证方法同时被一个线程调用,但这时有其它的线程正在调用该方法,
  26. //但并没有释放,死锁了,那么在这里就不会被执行,除非上面的线程释放了lock锁定的对象。这里的lock也可以理解为一个标识,线程1被锁定的对象
  27. //是否已经被释放,
  28. //如果没有释放,则无法继续访问lock块中的代码。
  29. lock (testlock)
  30. {
  31. // 如果该对象中lock(this)不释放(testlock与this指的是同一个对象),则其它线程如果调用该方法,则会出现直到lock(this)释放后才能继续调用。
  32. testlock.MotherCallYouDinner();
  33. testlock.DoWorkWithLock();
  34. }
  35. });
  36. th2.Start();
  37. Console.Read();
  38. }
  39. }
  40.  
  41. class TestLock
  42. {
  43. public static readonly object objLock = new object();
  44. /// <summary>
  45. /// 该方法,希望某人在工作的时候,其它人不要打扰(希望只有一个线程在执行)
  46. /// </summary>
  47. /// <param name="methodIndex"></param>
  48. public void DoWorkWithLock()
  49. {
  50. //锁当前对象
  51. lock (this)
  52. {
  53. Console.WriteLine("lock this");
  54. int i = ;
  55. while (true)
  56. {
  57. Console.WriteLine("At work, do not disturb...,Thread id is " + Thread.CurrentThread.ManagedThreadId.ToString());
  58. Thread.Sleep();
  59. if (i == )
  60. {
  61. break;
  62. }
  63. Console.WriteLine(i.ToString());
  64. i++;
  65. }
  66. }
  67. Console.WriteLine("lock dispose");
  68. }
  69. public void MotherCallYouDinner()
  70. {
  71. Console.WriteLine("Your mother call you to home for dinner.");
  72. }
  73. }
  74. }

测试

demo说明:main方法中,创建了一个对象testlock对象,线程1执行该对象的DoWorkWithLock方法,因为死锁(5s后释放),造成lock(this)无法释放,则导致了方法MotherCallYouDinner,DoWorkWithLock在线程2中无法被调用,直到lock(this)释放,lock(testlock)才能继续执行,可以这么理解,由于锁定的同一个对象,线程1释放了锁定的对象,其它线程才能访问。

lock(static readonly object)

那么通过lock(static object)方式呢,能不能保证lock块内的方法,同时只被一个线程执行呢,并且线程2能访问到MotherCallYouDinner方法。而不像上面出现的那种情况,如果不释放lock(this),导致线程2都无法执行代码逻辑。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7.  
  8. namespace LockTest
  9. {
  10. class Program
  11. {
  12. static void Main(string[] args)
  13. {
  14. TestLock testlock = new TestLock();
  15. Thread th = new Thread(() =>
  16. {
  17. //模拟死锁:造成死锁,使lock无法释放,在i=5时,跳出死循环,释放lock
  18. testlock.DoWorkWithLock();
  19. });
  20. th.Start();
  21. Thread.Sleep();
  22. Thread th2 = new Thread(() =>
  23. {
  24.  
  25. lock (testlock)
  26. {
  27. testlock.MotherCallYouDinner();
  28. testlock.DoWorkWithLock();
  29. }
  30. });
  31. th2.Start();
  32. Console.Read();
  33. }
  34. }
  35.  
  36. class TestLock
  37. {
  38. public static readonly object objLock = new object();
  39. /// <summary>
  40. /// 该方法,希望某人在工作的时候,其它人不要打扰(希望只有一个线程在执行)
  41. /// </summary>
  42. /// <param name="methodIndex"></param>
  43. public void DoWorkWithLock()
  44. {
  45. //锁
  46. lock (objLock)
  47. {
  48. Console.WriteLine("lock this");
  49. int i = ;
  50. while (true)
  51. {
  52. Console.WriteLine("At work, do not disturb...,Thread id is " + Thread.CurrentThread.ManagedThreadId.ToString());
  53. Thread.Sleep();
  54. if (i == )
  55. {
  56. break;
  57. }
  58. Console.WriteLine(i.ToString());
  59. i++;
  60. }
  61. }
  62. Console.WriteLine("lock dispose");
  63. }
  64. public void MotherCallYouDinner()
  65. {
  66. Console.WriteLine("Your mother call you to home for dinner.");
  67. }
  68. }
  69. }

测试

可以看到,将lock(this)更换为锁定私有的静态对象,线程2执行了,首先输出了“Your mother call you to home for dinner.”,同时实现了DoWorkWithLock方法中lock的代码块当前只被一个线程执行,直到lcok(objlock)被释放。因为锁定的对象,外部不能访问,线程2不再关心lock(this)是不是已经释放,都会执行,当然也保证了方法DoWorkWithLock同时被一个线程访问。

总结

1、避免使用lock(this),因为无法保证你提供的方法,在外部类中使用的时候,开发人员会不会锁定当前对象。

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

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

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

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

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

这里只是说明lock(this)的问题,虽然极端。但开发中,不能保证不会发生。

2、最好使用私有的静态只读的锁对象,保证不会影响其他逻辑的正常执行。

3、尽量避免死锁的发生。

资料,如果仍然不明白可以参考下面的链接

Why is lock(this) {…} bad?

来源:http://www.cnblogs.com/wolf-sun/p/8405541.html

C# 说说lock到底锁谁?(2)的更多相关文章

  1. [C#基础]说说lock到底锁谁?

    写在前面 最近一个月一直在弄文件传输组件,其中用到多线程的技术,但有的地方确实需要只能有一个线程来操作,如何才能保证只有一个线程呢?首先想到的就是锁的概念,最近在我们项目组中听的最多的也是锁谁,如何锁 ...

  2. C# 说说lock到底锁谁?(1)

    写在前面 最近一个月一直在弄文件传输组件,其中用到多线程的技术,但有的地方确实需要只能有一个线程来操作,如何才能保证只有一个线程呢?首先想到的就是锁的概念,最近在我们项目组中听的最多的也是锁谁,如何锁 ...

  3. [C#基础]说说lock到底锁谁?(补充与修改)

    摘要 今天在园子里面有园友反馈关于[C#基础]说说lock到底锁谁?文章中lock(this)的问题.后来针对文章中的例子,仔细想了一下,确实不准确,才有了这篇文章的补充,已经对文章中的demo进行修 ...

  4. 说说lock到底锁谁(II)?

    摘要 今天在园子里面有园友反馈关于[C#基础]说说lock到底锁谁?文章中lock(this)的问题.后来针对文章中的例子,仔细想了一下,确实不准确,才有了这篇文章的补充,已经对文章中的demo进行修 ...

  5. 说说lock到底锁谁(I)?

    写在前面 最近一个月一直在弄文件传输组件,其中用到多线程的技术,但有的地方确实需要只能有一个线程来操作,如何才能保证只有一个线程呢?首先想到的就是锁的概念,最近在我们项目组中听的最多的也是锁谁,如何锁 ...

  6. 说说lock到底要锁谁?

    波安搬... http://www.cnblogs.com/wolf-sun/p/4209521.html ---------------------------------------------- ...

  7. Coarse-Grained lock 粗粒度锁

    用一个锁Lock一组相关的对象 有时,需要按组来修改多个对象. 这样,在需要锁住其中一个的时候,必须连带地将其他的对象都上锁. 为每一个对象都加上一个锁是很繁琐的. 粗粒度锁是覆盖多个对象的单个锁. ...

  8. Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁

    (1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...

  9. JUC--Callable 以及Lock同步锁

    /** * 一.创建执行线程的方式三:实现Callable接口.相较于实现Runnable接口方式,方法可以有返回值,并且可以抛出异常 * 二.callable 需要FutureTask实现类的支持. ...

随机推荐

  1. c++ __declspec

    dllimport 和dllexport 用__declspec(dllexport),__declspec(dllimport)显式的定义dll接口给调用它的exe或dll文件,用 dllexpor ...

  2. Codeforces 1090D - Similar Arrays - [思维题][构造题][2018-2019 Russia Open High School Programming Contest Problem D]

    题目链接:https://codeforces.com/contest/1090/problem/D Vasya had an array of n integers, each element of ...

  3. CoreData 执行executefetchrequest卡死解决办法

    在大量使用GCD和block以后发现程序会卡死在executefetchrequest执行. 反复测试无果.添加锁也无效.想来想去没发现问题. 容忍了就当人品问题.2天以后实在忍无可忍. 替换perf ...

  4. js 整数型数组和字符型数组相互转换

    需求背景: 需要将 a = [1,2,3,4,5] 转换成  a = ['1','2','3','4','5'](整数型数组转换成字符型没找到直接的方法,思路就是先将数组转换成字符串,然后再将字符串转 ...

  5. pprint

    pprint = pretty printer 经常用来打印 字典.json 打印出的格式会是较为标准的格式 目的:方便调试,查看中间结果,因为觉得设断点调试相对麻烦. [运行环境:macOS 10. ...

  6. js 判断浏览器型号

    <html><head> <meta http-equiv="Content-Type" content="text/html;charse ...

  7. nodejs之querystring(查询字符串)

    querystring模块经常用在URL参数的处理,一共有四个方法: 1. stringify (字符串转对象) 2. parse (对象转字符串) 3. escape (对字符串进行URL编码) 4 ...

  8. 实现html页面自动刷新的几种方式

    自动页面刷新通常会用在对数据的实时性比较敏感的网站中,比如股票走势等,另外在普通的页面自动跳转中也会使用到页面自动刷新技术. 页面刷新我见过的有三种方式,下面来一一说明 1.通过在<head&g ...

  9. 数据库SQL的分组函数

    分组函数:(五个) 1···max(expr):求expr的最大值 }\ 2···min(expr):求expr的最小值 }-- 数据类型是有规定的 3···sum(expr):求expr的总和 }- ...

  10. window中的attrib命令

    attrib -s -h -r autorun.infattrib +s +h +r autorun.infattrib -s -h -r my.icoattrib +s +h +r my.ico