做网站报价明细表,长春企业建站系统模板,h5说 网站,网页设计尺寸1920在多线程环境中#xff0c;多个线程可能会同时访问同一个资源#xff0c;为了避免访问发生冲突#xff0c;可以根据访问的复杂程度采取不同的措施原子操作适用于简单的单个操作#xff0c;无锁算法适用于相对简单的一连串操作#xff0c;而线程锁适用于复杂的一连串操作原… 在多线程环境中多个线程可能会同时访问同一个资源为了避免访问发生冲突可以根据访问的复杂程度采取不同的措施原子操作适用于简单的单个操作无锁算法适用于相对简单的一连串操作而线程锁适用于复杂的一连串操作原子操作修改状态要么成功且状态改变要么失败且状态不变并且外部只能观察到修改前或者修改后的状态修改中途的状态不能被观察到.NET 中System.Threading.Interlocked 类提供了用于执行原子操作的函数这些函数接收引用参数ref也就是变量的内存地址然后针对该内存地址中的值执行原子操作无锁算法不使用线程锁通过修改操作的内容使它们满足原子操作的条件.NET 提供了一些线程安全的数据类型这些数据类型大量应用了无锁算法来提升访问速度在部分情况下仍需要线程锁System.Collections.Consurrent.CurrentBagSystem.Collections.Consurrent.CurrentDictionaryTKey, TValueSystem.Collections.Consurrent.CurrentQueueSystem.Collections.Consurrent.CurrentStack线程锁有获取锁Acquire和释放锁Release两个操作在获取锁之后和释放锁之前进行的操作保证在同一个时间只有一个线程执行操作内容无需改变所以线程锁具有很强的通用性线程锁有不同的种类下面将分别介绍自旋锁互斥锁混合锁读写锁自旋锁自旋锁Spinlock是最简单的线程锁基于原子操作实现它使用一个数值来表示锁是否已经被获取0表示未被获取1表示已经获取获取锁时会先使用原子操作设置数值为1然后检查修改前的值是否为0如果为0则代表获取成功否则继续重试直到成功为止释放锁时会设置数值为0其他正在获取锁的线程会在下一次重试时成功获取使用原子操作的原因是它可以保证多个线程同时把数值0修改到1时只有一个线程可以观察到修改前的值为0其他线程观察到修改前的值为1.NET 可以使用以下的类实现自旋锁System.Threading.Thread.SpinWaitSystem.Threading.SpinWaitSystem.Threading.SpinLock使用自旋锁有个需要注意的问题自旋锁保护的代码应该在非常短的时间内执行完毕如果代码长时间运行则其他需要获取锁的线程会不断重试并占用逻辑核心影响其他线程运行此外如果 CPU 只有一个逻辑核心自旋锁在获取失败时应该立刻调用 Thread.Yield 函数提示操作系统切换到其他线程因为一个逻辑核心同一时间只能运行一个线程在切换线程之前其他线程没有机会运行也就是切换线程之前自旋锁没有机会被释放互斥锁由于自旋锁不适用于长时间运行它的使用场景比较有限更通用的线程锁是操作系统提供的基于原子操作与线程调度实现的互斥锁Mutex与自旋锁一样操作系统提供的互斥锁内部有一个数值表示是否已经被获取不同的是当获取锁失败时它不会反复重试而是安排获取锁的线程进入等待状态并把线程对象添加到锁关联的队列中另一个线程释放锁时会检查队列中是否有线程对象如果有则通知操作系统唤醒该线程因为处于等待状态的线程没有运行即使长时间不释放也不会消耗 CPU 资源但让线程进入等待状态与从等待状态唤醒并调度运行可能会花费毫秒级的时间与自旋锁重试所需的纳秒级时间相比非常的长.NET 提供了 System.Threading.Mutex 类这个类包装了操作系统提供的互斥锁它是可重入的已经获取锁的线程可以再次执行获取苏锁的操作但释放锁的操作也要执行相同的次数可重入的锁又叫递归锁Recursive Lock递归锁内部使用一个计数器记录进入次数同一个线程每获取一次就加1释放一次就减1减1后如果计数器变为0就执行真正的释放操作一般用在嵌套调用的多个函数中Mutex 类的另一个特点是支持跨进程使用创建时通过构造函数的第二个参数可以传入名称如果一个进程获取了锁那么在释放该锁前的另一个进程获取同样名称的锁需要等待如果进程获取了锁但是在退出之前没有调用释放锁的方法那么锁会被操作系统自动释放其他当前正在等待锁锁被自动释放前进入等待状态的进程会收到 AbandonedMutexException 异常跨进程锁通常用于保护多个进程共享的资源或者防止程序多重启动混合锁互斥锁 Mutex 使用时必须创建改类型的实例因为实例包含了非托管的互斥锁对象开发者必须在不使用锁后尽快调用 Dispose 函数释放非托管资源并且因为获取锁失败后会立刻安排线程进入等待总体上性能比较低.NET 提供了更通用而且更高性能的混合锁Monitor任何引用类型的对象都可以作为锁对象不需要事先创建指定类型的实例并且涉及的非托管资源由 .NET 运行时自动释放不需要手动调用释放函数获取和释放混合锁需要使用 System.Threading.Monitor 类中的函数C# 提供了 lock 语句来简化通过 Monitor 类获取和释放的代码混合锁的特征是在获取锁失败后像自旋锁一样重试一定的次数超过一定次数之后.NET Core 2.1 是30次再安排当前进程进入等待状态混合锁的好处是如果第一次获取锁失败但其他线程马上释放了锁当前线程在下一轮重试可以获取成功不需要执行毫秒级的线程调度处理而如果其他线程在短时间内没有释放锁线程会在超过重试次数之后进入等待状态以避免消耗 CPU 资源因此混合锁适用于大部分场景读写锁读写锁ReaderWriterLock是一个具有特殊用途的线程锁适用于频繁读取且读取需要一定时间的场景共享资源的读取操作通常是可以同时执行的而普通的互斥锁不管是读取还是修改操作都无法同时执行如果多个线程为了读取操作而获取互斥锁那么同一时间只有一个线程可以执行读取操作在频繁读取的场景下会对吞吐量造成影响读写锁分为读取锁和写入锁线程可以根据对共享资源的操作类型选择获取读写锁还是写入锁读取锁可以被多个线程同时获取写入锁不可以被多个线程同时获取而且读取锁和写入锁不可以被不同的线程同时获取.NET 提供的 System.Threading.ReaderWriterLockSlim 类实现了读写锁读写锁也是一个混合锁Hybird Lock,在获取锁时通过自旋重试一定的次数再进入等待状态此外它还支持同一个线程先获取读写锁然后再升级为写入锁适用于“需要先获取读写锁然后读取共享数据判断是否需要修改需要修改时再获取写入锁”的场景参考资料《.NET Core 底层入门》如果阅读文章后有所收获希望您可以点击阅读原文在博客园为作者点一个推荐感激不尽!!!