- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
合集: .NET Core多线程温故知新 。
。
去年换工作时系统复习了一下.NET Core多线程相关专题,学习了一线码农老哥的《.NET 5多线程编程实战》课程,我将复习的知识进行了总结形成本专题.
本篇,我们来复习一下.NET中锁机制的相关知识点,预计阅读时间10分钟.
对某个共享代码区域(临界区)进行串行访问,使用lock来 保证串行的安全 .
lock (lockMe) { dict.Add(i.ToString(), DateTime.Now); }
通过ILSpy反编译查看可以知道,lock是个语法糖, 编译后其实是Monitor.Enter 和 Monitor.Exit 的封装 .
try { Monitor.Enter(lockMe, ref lockTake); dict.Add(i.ToString(), DateTime.Now); } finally { if (lockTake) { Monitor.Exit(lockMe); } }
首先,编译器要求lock中的所对象必须是引用类型.
其次,因为lock会用到对象头中的同步块索引来进行同步,值类型没有堆中的数据.
static 的作用域在AppDomain下都可见,此时在多线程环境中,通过static共享变量的方式来同步,不可避免会出现锁竞争。如果能将作用域范围缩小,比如缩小到Thread级别,就可以避免锁竞争。例如:ConcurrentBag就是一个好的例子.
ThreadStatic(Attribute):当前线程拿到的是定义好的值,其他线程拿到的可能是默认值(值类型可能是0,引用类型可能是null,需要注意容错).
ThreadLocal:与ThreadStatic最大的区别在于ThreadStatic只在第一个线程初始化,ThreadLocal则会为每个线程初始化.
用来做数据库连接池:DB连接池 基于 ThreadLocal实现,每个线程只能看见自己的请求队列; 。
用来做链式追踪:比如Skywalking或Zipkin等,用到ThreadLocal做本地存储,记录完整的调用链条如:A -> B -> C -> D; 。
这种锁是基于Windows底层的内核数据结构来维护线程之间的同步,比如:
AutoResetEvent / ManualResetEvent 。
Semaphore 。
Mutex 。
需要从用户态切换到内核态,相对来说比较重量级,相对耗费时间;内核模式的锁,不仅可用于创建线程同步,还可以创建进程同步.
例如下面的代码:
lock (obj) { ... // todo [1ms] }
大部分都是在临界区进行等待时间很短(比如1ms)的加锁,能不能让thread在CLR或C#层面内旋(自旋)一下,从而提高性能呢?使用用户态锁就可以避免上下文切换和内核切换带来的高开销.
保持线程在用户态又要尽可能少的消耗CPU时间 。
SpinLock在用法上和lock关键字差不多的.
class Program { public static SpinLock spinLock = new SpinLock(); public static int counter = 0 ; static void Main( string [] args) { Parallel.For( 1 , 1000001 , (i) => { var lockTaken = false ; spinLock.Enter( ref lockTaken); ++ counter; spinLock.Exit(); } }); Console.WriteLine($ " counter={counter} " ); Console.ReadLine(); }
CPU直接操作的,主要用在一些简单类型上:
read 。
operation 。
write 。
class Program { public static SpinLock spinLock = new SpinLock(); public static int counter = 0 ; static void Main( string [] args) { Parallel.For( 1 , 1000001 , (i) => { Interlocked.Increment( ref counter, 1 ); }); Console.WriteLine($ " counter={counter} " ); Console.ReadLine(); }
混合锁: 用户态模式+内核态模式 。
它是如何实现的?
它是如何实现的?
这个锁的内核版是 ReaderWriterLock,不带Slim就代表是内核态的锁.
这个锁顾名思义是读写锁,意思是:读可以并行,但写只能串行。EnterWriteLock() 需要等待所有的reader或writer锁结束,才能开始 。
这个锁可以实现类似MapReduce的效果.
它是如何实现的?
基于ManualResetEvent事件做了底层封装.
.NET中都有哪些线程安全的集合类型?
ConcurrentBag 对应非线程安全类型:List 。
ConcurrentQueue 对应非线程安全类型:Queue 。
ConcurrentStack 对应非线程安全类型:Stack 。
ConcurrentDictionary 对应非线程安全类型:Dictionary 。
BlockingCollection 意为 阻塞集合.
线程安全的集合 可以转换为 阻塞集合,只要它实现了IProducerConsumerCollection接口BlockingCollection可以实现类似发布订阅的业务场景应用:
生产端Add进去发布的消息 。
消费者端通过GetConsumingEnumerable()方法阻塞等待发布的消息 。
观察现象 。
业务场景:自己用ConcurrentDictionary封装了一个Cache 。
FullGC 将 LOH 上的对象回收了 。
所有>=85000byte的都会被纳入LOH 。
观察源码 。
Values方法每次都会生成一个新的List集合对象进行返回,每个对象都是大对象 。
如何改进 。
禁止调用Values方法 。
借助lock + Dictionary实现类似操作避免每次生成新的List集合对象 。
观察现象 。
业务场景:自己用ConcurrentDictionary封装了一个Redis连接池缓存 。
借助GetOrAdd实现的CreateInstance方法未能实现线程安全导致连接池被大量反复创建 。
观察源码 。
GetOrAdd方法中的valueFactory不是线程安全的 。
如何改进 。
借助Lazy改造字典的Value对象,保证创建方法只被执行一次,比如:将RedisConnection改为Lazy 。
同样的代码,通过共享变量控制工作线程是否要结束自己,在Debug模式下没有问题,但是在Release模式下有问题.
JIT提供了错误的决策导致CPU在解析代码时做了优化,将 共享变量 存放在了CPU的寄存器中.
Release模式 。
查看memory中的共享变量的值 。
CPU寄存器 。
查看共享变量的值 。
使用CancellationToken做取消 。
不用Cache,都读内存address中的对象,性能会相对较低 。
将共享变量 改为 易变结构,比如:private bool _shouldStop 改为 private volatile bool _shouldStop 。
本篇,我们复习了锁机制相关的知识点。下一篇,我们将复习一下常见的.NET多线程相关的性能优化实践.
一线码农,腾讯课堂《 .NET 5多线程编程实战 》 。
不明作者,《Task调度与await》 。
。
作者: 周旭龙 。
出处: https://edisonchou.cnblogs.com 。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接.
最后此篇关于.NETCore多线程(4)锁机制的文章就讲到这里了,如果你想了解更多关于.NETCore多线程(4)锁机制的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
广播的原则 如果两个数组的后缘维度(从末尾开始算起的维度)的轴长度相符或其中一方的长度为1,则认为它们是广播兼容的。广播会在缺失维度和(或)轴长度为1的维度上进行。 在上面的对arr每一列减去列
之前在讲 MySQL 事务隔离性提到过,对于写操作给读操作的影响这种情形下发生的脏读、不可重复读、虚读问题。是通过MVCC 机制来进行解决的,那么MVCC到底是如何实现的,其内部原理是怎样的呢?我们要
我创建了一个 JavaScript 对象来保存用户在 ColorBox 中检查复选框时设置的值。 . 我对 jQuery 和“以正确的方式”编程 JavaScript 比较陌生,希望确保以下用于捕获用
我为了回答aquestion posted here on SO而玩示例,发现很难理解python的import *破坏作用域的机制。 首先是一点上下文:这个问题不涉及实际问题;我很清楚from fo
我想让我的类具有标识此类的参数 ID。例如我想要这样的东西: class Car { public static virtual string ID{get{return "car";}} }
更新:我使用的是 Java 1.6.34,没有机会升级到 Java 7。 我有一个场景,我每分钟只能调用一个方法 80 次。它实际上是由第 3 方编写的服务 API,如果您多次调用它,它会“关闭”(忽
希望这对于那些使用 Javascript 的人来说是一个简单的答案...... 我有一个日志文件,该文件正在被一个脚本监视,该脚本将注销中的新行提供给任何连接的浏览器。一些人评论说,他们希望看到的更多
我们正在开发针对 5.2 开发的 PHP 应用程序,但我们最近迁移到了 PHP 5.3。我们没有时间去解决所有迁移到 PHP 5.3 的问题。具体来说,我们有很多消息: Declaration of
简介 在实现定时调度功能的时候,我们往往会借助于第三方类库来完成,比如: quartz 、 spring schedule 等等。jdk从1.3版本开始,就提供了基于 timer 的定时调度功能。
Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端。这就需要有一种可以在两端传输数据的协议。Java序列化机制就是为了解决这个问题而
我将编写自己的自定义控件,它与 UIButton 有很大不同。由于差异太大,我决定从头开始编写。所以我所有的子类都是 UIControl。 当我的控件在内部被触摸时,我想以目标操作的方式触发一条消息。
在我的代码中,在创建 TIdIMAP4 连接之前,我设置了一大堆 SASL 机制,希望按照规定的“最好到最差”顺序,如下所示: IMAP.SASLMechanisms.Add.SASL := mIdS
在 Kubernetes 中,假设我们有 3 个 pod,它们物理上托管在节点 X、Y 和 Z 上。当我使用“kubectl expose”将它们公开为服务时,它们都是集群中的节点(除了 X、Y 和
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
我知道进程间通信 (ipc) 有几种方法,例如: 文件 信号 socket 消息队列 管道 命名管道 信号量 共享内存 消息传递 内存映射文件 但是我无法找到将这些机制相互比较并指出它们在不同环境中的
当我尝试连接到 teradata 时,出现了TD2 机制不支持单点登录 错误。 在 C# 中,我遇到了类似的问题,我通过添加 connectionStringBuilder.Authetication
我有一个带有 JSON API 的简单 Javascript 应用程序。目前它在客户端运行,但我想将它从客户端移动到服务器。我习惯于学习新平台,但在这种情况下,我的时间非常有限 - 所以我需要找到绝对
我想了解事件绑定(bind)/解除绑定(bind)在浏览器中是如何工作的。具体来说,如果我删除一个已经绑定(bind)了事件的元素,例如使用 jQuery:$("#anElement").remove
我不是在寻找具体答案,只是一个想法或提示。我有以下问题: Android 应用程序是 Web 服务的客户端。它有一个线程,通过 http 协议(protocol)发送事件(带有请求 ID 的 XML
我正在研究 FreeBSD TCP/IP 栈。似乎有 2 种 syn flood 机制,syncookies 和 syncache。我的问题是关于 syncookies,它是从头开始还是在 SYN 队
我是一名优秀的程序员,十分优秀!