一. 整体介绍

温馨提示:内核模式锁,在不到万不得已的情况下,不要使用它,因为代价太大了,有很多种替代方案。

  内核模式锁包括:

    ①:事件锁

    ②:信号量

    ③:互斥锁

    ④:读写锁

    ⑤:动态锁

二. 事件锁

事件锁包括:

A. 自动事件锁(AutoResetEvent)

  使用场景:可以用此锁实现多线程环境下某个变量的自增.

  现实场景: 进站火车闸机,我们用火车票来实现进站操作.

  true: 表示终止状态,闸机中没有火车票

  false: 表示非终止状态,闸机中此时有一张火车票

B.手动事件锁(ManualResetEvent)

  现实场景:有人看守的铁道栅栏(和自动事件锁不一样,不能混用)

  true: 栅栏没有合围,没有阻止行人通过铁路

  false:栅栏合围了, 阻止行人通过

* 下面案例发现,锁不住,自增仍然是无序的输出了.

* 核心方法:WaitOne和Set

 代码实践-自动事件锁:

 1  static AutoResetEvent autoResetLock1 = new AutoResetEvent(true);2  static AutoResetEvent autoResetLock2 = new AutoResetEvent(false);3  static int num2 = 0;4  {5                 //1. 能输出6                 {7                     autoResetLock1.WaitOne();8                     Console.WriteLine("autoResetLock1检验通过,可以通行");9                     autoResetLock1.Set();
10                 }
11
12                 //2. 不能输出
13                 {
14                     autoResetLock2.WaitOne();
15                     Console.WriteLine("autoResetLock2检验通过,可以通行");
16                     autoResetLock2.Set();
17                 }
18
19                 //3.下面代码的结果:num从0-249,有序的发现可以锁住。
20                 {
21                     for (int i = 0; i < 5; i++)
22                     {
23                         Task.Factory.StartNew(() =>
24                         {
25                             for (int j = 0; j < 50; j++)
26                             {
27                                 try
28                                 {
29                                     autoResetLock1.WaitOne();
30                                     Console.WriteLine(num2++);
31                                     autoResetLock1.Set();
32                                 }
33                                 catch (Exception ex)
34                                 {
35                                     Console.WriteLine(ex.Message);
36                                 }
37
38                             }
39                         });
40                     }
41                 }
42             }

代码实践-手动事件锁:

 1          static int num2 = 0;2          static ManualResetEvent mreLock = new ManualResetEvent(true);3          //下面代码锁不住,仍然是无序的输出了4                 {5                     for (int i = 0; i < 5; i++)6                     {7                         Task.Factory.StartNew(() =>8                         {9                             for (int j = 0; j < 50; j++)
10                             {
11                                 try
12                                 {
13                                     mreLock.WaitOne();
14                                     Console.WriteLine(num2++);
15                                     mreLock.Set();
16                                 }
17                                 catch (Exception ex)
18                                 {
19                                     Console.WriteLine(ex.Message);
20                                 }
21
22                             }
23                         });
24                     }
25                 }

三. 信号量

信号量:

  * 核心类:Semaphore,通过int数值来控制线程个数。

  * 通过观察构造函数 public Semaphore(int initialCount, int maximumCount);:

  * initialCount: 可以同时授予的信号量的初始请求数。

  * maximumCount: 可以同时授予的信号量的最大请求数。

  * static Semaphore seLock = new Semaphore(1, 1); //表示只允许一个线程通过

* 下面的案例可以有序的输出。

* 核心方法:WaitOne和Release

 代码实践:

 1              static Semaphore seLock = new Semaphore(1, 1); //只允许一个线程通过 2                 //下面代码锁住了,可以有序的输出3                 {4                     for (int i = 0; i < 5; i++)5                     {6                         Task.Factory.StartNew(() =>7                         {8                             for (int j = 0; j < 50; j++)9                             {
10                                 try
11                                 {
12                                     seLock.WaitOne();
13                                     Console.WriteLine(num2++);
14                                     seLock.Release();
15                                 }
16                                 catch (Exception ex)
17                                 {
18                                     Console.WriteLine(ex.Message);
19                                 }
20
21                             }
22                         });
23                     }
24                 }

四. 互斥锁

互斥锁:

  核心方法:WaitOne和ReleaseMutex

  下面案例可以锁住,有序输出

总结以上三种类型的锁,都有一个WaitOne方法,观察源码可知,都继承于WaitHandle类。

 代码实践:

 1       static Mutex mutex = new Mutex();2         //下面代码锁住了,可以有序的输出3                 {4                     for (int i = 0; i < 5; i++)5                     {6                         Task.Factory.StartNew(() =>7                         {8                             for (int j = 0; j < 50; j++)9                             {
10                                 try
11                                 {
12                                     mutex.WaitOne();
13                                     Console.WriteLine(num2++);
14                                     mutex.ReleaseMutex();
15                                 }
16                                 catch (Exception ex)
17                                 {
18                                     Console.WriteLine(ex.Message);
19                                 }
20
21                             }
22                         });
23                     }
24                 }

五. 读写锁

读写锁(ReaderWriterLock):

  背景:多个线程读,一个线程写,如果写入的时间太久,此时读的线程会被卡死,这个时候就要用到读写锁了。

  锁读的两个核心方法:AcquireReaderLock和ReleaseReaderLock。

  锁写的两个核心方法:AcquireWriterLock和ReleaseWriterLock。

 代码实践:

 1        static ReaderWriterLock rwlock = new ReaderWriterLock();2         private void button24_Click(object sender, EventArgs e)3         {4             #region 01-读写锁5             {6                 //开启5个线程执行读操作7                 for (int i = 0; i < 5; i++)8                 {9                     Task.Run(() =>
10                     {
11                         Read();
12                     });
13                 }
14                 //开启1个线程执行写操作
15                 Task.Factory.StartNew(() =>
16                 {
17                     Write();
18                 });
19             }
20             #endregion
21
22         }
23         /// <summary>
24         /// 线程读
25         /// </summary>
26         static void Read()
27         {
28             while (true)
29             {
30                 Thread.Sleep(10);
31                 rwlock.AcquireReaderLock(int.MaxValue);
32                 Console.WriteLine("当前 t={0} 进行读取 {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now);
33                 rwlock.ReleaseReaderLock();
34             }
35         }
36         /// <summary>
37         /// 线程写
38         /// </summary>
39         static void Write()
40         {
41             while (true)
42             {
43                 Thread.Sleep(300);
44                 rwlock.AcquireWriterLock(int.MaxValue);
45                 Console.WriteLine("当前 t={0} 进行写入 {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now);
46                 rwlock.ReleaseWriterLock();
47             }
48         }

六. 动态锁

动态锁(CountdownEvent):

  * 作用:限制线程数的一个机制。

  * 业务场景:有Orders、Products、Users表,我们需要多个线程从某一张表中读取数据。

  * 比如:Order表10w,10个线程读取。(每个线程读1w)

       Product表5w,5个线程读取。(每个线程读1w)

         User表2w,2个线程读取。(每个线程读1w)

三个核心方法:

  ①.Reset方法:重置当前的线程数量上限。(初始化的时候,默认设置一个上限)

  ②.Signal方法:将当前的线程数量执行减1操作。(使用一个thread,这个线程数量就会减1操作,直到为0后,继续下一步)

  ③.Wait方法:相当于我们的Task.WaitAll方法。

代码实践:

 1  //初始化线程数量上限为10.2         static CountdownEvent cdLock = new CountdownEvent(10);3         private void button25_Click(object sender, EventArgs e)4         {5             //加载Orders搞定6             cdLock.Reset(10);7             for (int i = 0; i < 10; i++)8             {9                 Task.Factory.StartNew(() =>
10                 {
11                     LoadOrder();
12                 });
13             }
14             cdLock.Wait();
15             Console.WriteLine("所有的Orders都加载完毕。。。。。。。。。。。。。。。。。。。。。");
16
17             //加载Product搞定
18             cdLock.Reset(5);
19             for (int i = 0; i < 5; i++)
20             {
21                 Task.Run(() =>
22                 {
23                     LoadProduct();
24                 });
25             }
26             cdLock.Wait();
27             Console.WriteLine("所有的Products都加载完毕。。。。。。。。。。。。。。。。。。。。。");
28
29             //加载Users搞定
30             cdLock.Reset(2);
31             for (int i = 0; i < 2; i++)
32             {
33                 Task.Factory.StartNew(() =>
34                 {
35                     LoadUser();
36                 });
37             }
38             cdLock.Wait();
39             Console.WriteLine("所有的Users都加载完毕。。。。。。。。。。。。。。。。。。。。。");
40
41             Console.WriteLine("所有的表数据都执行结束了。。。恭喜恭喜。。。。");
42             Console.Read();
43         }
44         static void LoadOrder()
45         {
46             //书写具体的业务逻辑
47             Console.WriteLine("当前LoadOrder正在加载中。。。{0}", Thread.CurrentThread.ManagedThreadId);
48             //线程数量减1
49             cdLock.Signal();
50
51         }
52         static void LoadProduct()
53         {
54             //书写具体的业务逻辑
55             Console.WriteLine("当前LoadProduct正在加载中。。。{0}", Thread.CurrentThread.ManagedThreadId);
56             //线程数量减1
57             cdLock.Signal();
58         }
59         static void LoadUser()
60         {
61             //书写具体的业务逻辑
62             Console.WriteLine("当前LoadUser正在加载中。。。{0}", Thread.CurrentThread.ManagedThreadId);
63             //线程数量减1
64             cdLock.Signal();
65         }

第十二节:深究内核模式锁的使用场景(自动事件锁、手动事件锁、信号量、互斥锁、读写锁、动态锁)相关推荐

  1. 自旋锁/互斥锁/读写锁/递归锁的区别与联系

    自旋锁 互斥锁 读写锁 递归锁 互斥锁(mutexlock): 最常使用于线程同步的锁:标记用来保证在任一时刻,只能有一个线程访问该对象,同一线程多次加锁操作会造成死锁:临界区和互斥量都可用来实现此锁 ...

  2. java读写锁降级_java的读写锁中锁降级的问题

    读写锁是什么我就不多说了,下面说什么是锁降级 锁降级: 锁降级指的是写锁降级成为读锁.如果当前线程拥有写锁,然后将其释放,最后再获取读锁,这种分段完成的过程不能称之为锁降级.锁降级是指把持住(当前拥有 ...

  3. java dom4j读写锁,java锁的深度化-重入锁,读写锁,乐观锁,悲观锁

    1.重入锁 目的:避免死锁的现象 锁作为并发共享数据,保证一致性的工具,在java平台有多种实现synchronized(重量级)和ReentrantLock(轻量级)等等,这些已经写好提供的锁为我们 ...

  4. JAVA 读写锁中锁降级的必要性

    既然大家看到了这篇博客,也应该都大概了解了读写锁的一些概念,咱们直接上主题,读写锁中为什么要用锁降级: 先引用书上的一段话说说锁降级的概念:         锁降级指的是写锁降级成为读锁.如果当前线程 ...

  5. 从自旋锁、睡眠锁、读写锁到 Linux RCU 机制讲解

    总结一下 O/S 课程里面和锁相关的内容. 本文是 6.S081 课程的相关内容总结回顾结合 Real World 的 Linux 讲解各种锁和 RCU lock free 机制原理, 前置知识是基本 ...

  6. 同步方法中的锁对象_互斥锁与读写锁:如何使用锁完成Go程同步?

    图转自https://colobu.com/2018/12/18/dive-into-sync-mutex/ 这张图容易让人产生误解,容易让人误以为goroutine1获取的锁,只有goroutine ...

  7. 【剧前爆米花--爪哇岛寻宝】常见的锁策略——乐观锁、读写锁、重量级锁、自旋锁、公平锁、可重入锁等

    作者:困了电视剧 专栏:<JavaEE初阶> 文章分布:这是关于操作系统锁策略的文章,包括乐观锁.读写锁.重量级锁.自旋锁.公平锁.可重入锁等,希望对你有所帮助! 目录 乐观锁和悲观锁 悲 ...

  8. 【Linux内核】RW读写锁机制

    读写锁机制 Linux内核中读写锁的机制是一种多读单写的锁机制,它允许多个读操作同时进行,但只能有一个写操作进行.当有写操作时,所有读操作都会被阻塞,直到写操作完成. 在内核中,读写锁主要由以下两个结 ...

  9. java锁(公平锁和非公平锁、可重入锁(又名递归锁)、自旋锁、独占锁(写)/共享锁(读)/互斥锁、读写锁)

    前言 本文对Java的一些锁的概念和实现做个整理,涉及:公平锁和非公平锁.可重入锁(又名递归锁).自旋锁.独占锁(写)/共享锁(读)/互斥锁.读写锁 公平锁和非公平锁 概念 公平锁是指多个线程按照申请 ...

最新文章

  1. Leetcode 199. 二叉树的右视图 解题思路及C++实现
  2. POJ - 3261 Milk Patterns(二分+后缀数组)
  3. cni k8s 插件安装_K8S 之 Flannel网络插件安装
  4. 利用SecureCRT在linux与Windows之间传输文件
  5. Redis 持久化——RDB
  6. Android OpenGLES2.0(十四)——Obj格式3D模型加载
  7. python做单元测试_如何使用python做单元测试?
  8. sparksql 操作hive_三十六、图解SparkSQL运行原理
  9. 全幅與APS-C MTF曲線解讀說明
  10. 《R语言初学指南》一1.2 向量
  11. Tomcat下载——tomcat7、tomcat8、tomcat9官网下载链接
  12. 前端如何播放m3u8格式的视频
  13. 填空什么的月牙_部编一年级上册语文第四单元知识梳理填空,附答案
  14. Linux 返回根目录,返回主目录
  15. 联想sr550服务器虚拟机,联想(Lenovo)SR550
  16. 阿里云OSS对象存储-图文详解
  17. [汇编语言] 循环与分支程序设计 例题
  18. 超级牛逼的立体画,太厉害了!
  19. Android app本地图片转换成Drawable对象的方法
  20. iOS 图片转base64编码

热门文章

  1. Golang tcp转发 remoteAddr错误
  2. C# Json转对象
  3. Python——assert(断言函数)
  4. ASP.NET MVC中的模型装配 封装方法 非常好用
  5. JVM JRE JDK,这些东西到底是什么?(转载)
  6. 用WebORB实现flex + .net后台的Remoting
  7. php对话框制作,织梦系统“提示窗口对话框类”详解,oxwindow.class.php、catalog_do.php...
  8. java的jsp要下载吗_jsp、java下载附件
  9. controller调用controller的方法_SpringCloud(5):Feign整合Ribbon和Hystrix来进行远程调用与服务熔断...
  10. 信号调制疑问_DSM 调制器simulink仿真分析