【转】【Thread】ReaderWriterLock 读写锁

ReaderWriterLock类

  通常来讲,一个类型的实例对于并行的读操作是线程安全的,但是并行地根性操作则不是(并行地读和更新也不是)。 这对于资源也是一样的,比如一个文件。当保护类型的实例安全时,使用一个简单的排它锁即解决问题,但是当有很多的读操作而偶然的更新操作这就很不合理的限制了并发。一个例子就是这在一个业务程序服务器中,为了快速查找把数据缓存到静态字段中。 在这个方案中,ReaderWriterLock类被设计成提供最大容量的锁定。

  ReaderWriterLock为读和写的锁提供了不同的方法——AcquireReaderLock和AcquireWriterLock。两个方法都需要一个超时参数,并且在超时发生后抛出ApplicationException异常(不同于大多数线程类的返回false等效的方法)。超时发生相当容易在资源争用严重的时候。

  调用 ReleaseReaderLock或ReleaseWriterLock释放锁。 这些方法支持嵌套锁,ReleaseLock方法也支持一次清除所有嵌套级别的锁。(你可以随后调用RestoreLock类重新锁定相同的级别,它在ReleaseLock之前执行——如此来模仿Monitor.Wait的锁定切换行为)。

  你可以调用AcquireReaderLock开始一个read-lock ,然后通过UpgradeToWriterLock把它升级为write-lock。这个方法返回一个可能被用于调用DowngradeFromWriterLock的信息。这个方式允许读程序临时地请求写访问同时不必必须在降级之后重新排队列。

  在接下来的这个例子中,4个线程被启动:一个不停地往列表中增加项目;另一个不停地从列表中移除项目;其它两个不停地报告列表中项目的个数。前两者获得写的锁,后两者获得读的锁。每个锁的超时参数为10秒。(异常处理一般要使用来捕捉ApplicationException,这个例子中出于方便而省略了).

例子:

class Program
{
     static ReaderWriterLock rw = new ReaderWriterLock ();
     static List <int> items = new List <int> ();
     static Random rand = new Random ();

     static void Main (string[] args)
     {
        new Thread (delegate() { while (true) AppendItem(); } ).Start();
        new Thread (delegate() { while (true) RemoveItem(); } ).Start();
        new Thread (delegate() { while (true) WriteTotal(); } ).Start();
        new Thread (delegate() { while (true) WriteTotal(); } ).Start();
     }

     static int GetRandNum (int max)
     { lock (rand) return rand.Next (max); }

     static void WriteTotal()
     {
        rw.AcquireReaderLock (10000);
        int tot = 0; foreach (int i in items) tot += i;
        Console.WriteLine (tot);
        rw.ReleaseReaderLock();
     }

     static void AppendItem ()
     {
        rw.AcquireWriterLock (10000);
        items.Add (GetRandNum (1000));
        Thread.SpinWait (400);
        rw.ReleaseWriterLock();
      }

     static void RemoveItem ()
     {
        rw.AcquireWriterLock (10000);
        if (items.Count > 0)
              items.RemoveAt (GetRandNum (items.Count));
        rw.ReleaseWriterLock();
     }
}        

往List中加项目要比移除快一些,这个例子在AppendItem中包含了SpinWait来保持项目总数平衡。

按照请求到达的顺序,一共有四种 :
      Reader-Reader,第二个不需等待,直接获得读控制权; 
      Reader-Writer,第二个需要等待第一个调用ReleaseReaderLock()释放读控制权后,才能获得写控制权; 
      Writer-Writer,第二个需要等待第一个调用ReleaseWriterLock()释放写控制权后,才能获得写控制权; 
      Writer-Reader,第二个需要等待第一个调用ReleaseWriterLock()释放写控制权后,才能获得读控制权。

原文链接:http://www.cnblogs.com/coderzh/articles/1586268.html

时间: 2024-11-12 23:34:56

【转】【Thread】ReaderWriterLock 读写锁的相关文章

读写锁学习(1)——ReaderWriterLock学习

读写锁的目的:将读和写分离,可以实现多个用户的读操作,但是写操作只能有一个用户执行. 实例: using System; using System.Threading; namespace ProcessTest { class Program { static int theResource = 0; static ReaderWriterLock rwl = new ReaderWriterLock(); static void Main(string[] args) { //分别创建2个读

zbb20180929 thread 自旋锁、阻塞锁、可重入锁、悲观锁、乐观锁、读写锁、对象锁和类锁

1.自旋锁自旋锁可以使线程在没有取得锁的时候,不被挂起,而转去执行一个空循环,(即所谓的自旋,就是自己执行空循环),若在若干个空循环后,线程如果可以获得锁,则继续执行.若线程依然不能获得锁,才会被挂起.使用自旋锁后,线程被挂起的几率相对减少,线程执行的连贯性相对加强.因此,对于那些锁竞争不是很激烈,锁占用时间很短的并发线程,具有一定的积极意义,但对于锁竞争激烈,单线程锁占用很长时间的并发程序,自旋锁在自旋等待后,往往毅然无法获得对应的锁,不仅仅白白浪费了CPU时间,最终还是免不了被挂起的操作 ,

C# lock 语法糖实现原理--《.NET Core 底层入门》之自旋锁,互斥锁,混合锁,读写锁

原文:C# lock 语法糖实现原理--<.NET Core 底层入门>之自旋锁,互斥锁,混合锁,读写锁 在多线程环境中,多个线程可能会同时访问同一个资源,为了避免访问发生冲突,可以根据访问的复杂程度采取不同的措施 原子操作适用于简单的单个操作,无锁算法适用于相对简单的一连串操作,而线程锁适用于复杂的一连串操作 原子操作 修改状态要么成功且状态改变,要么失败且状态不变,并且外部只能观察到修改前或者修改后的状态,修改中途的状态不能被观察到 .NET 中,System.Threading.Inte

Java并发程序设计(15)并发锁之读写锁(续二)写锁降级

1.1.1. 读写锁应用之三写锁降级 ReentrantReadWriteLock还具有写锁降级的特点,而这跟可重入性有一些关系. (1)持有写锁时可以降级为读锁. (2)持有读锁时不能升级为写锁. ReentrantReadWriteLock和ReentrantLock相似的是都有一个特点,就是可重入.可重入指已经获取到锁的线程可以再次获取锁,保证lock和unlock的次数相同即可. package com.test.concurrence; import java.util.Random;

ReentrantReadWriteLock读写锁的使用2

本文可作为传智播客<张孝祥-Java多线程与并发库高级应用>的学习笔记. 这一节我们做一个缓存系统. 在读本节前 请先阅读 ReentrantReadWriteLock读写锁的使用1 第一版 public class CacheDemo { private Map<String, Object> cache = new HashMap<String, Object>(); public static void main(String[] args) { CacheDem

linux 读写锁应用实例

转自:http://blog.csdn.net/dsg333/article/details/22113489 /*使用读写锁实现四个线程读写一段程序的实例,共创建了四个新的线程,其中两个线程用来读取数据,另外两个线程用来写入数据.在任意时刻,如果有一个线程在写数据,将阻塞所有其他线程的任何操作.*/#include <errno.h>#include <pthread.h>#include <stdio.h>#include <stdlib.h>#incl

读写锁ReadWriteLock和缓存实例

读写锁:多个读锁不互斥,读锁与些锁互斥,写锁与写锁互斥.即:读的时候不允许写,写的时候不允许读,可以同时读. synchronized关键字和普通的Lock构造的锁,会造成读与读之间的互斥,因此读写锁可提高性能. 例子1:三个线程同时对一个共享数据进行读写. import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantRea

Linux多线程实践(6) --Posix读写锁解决读者写者问题

Posix读写锁 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_wrlock(pthre

深入浅出 Java Concurrency (14): 锁机制 part 9 读写锁 (ReentrantReadWriteLock) (2)[转]

这一节主要是谈谈读写锁的实现. 上一节中提到,ReadWriteLock看起来有两个锁:readLock/writeLock.如果真的是两个锁的话,它们之间又是如何相互影响的呢? 事实上在ReentrantReadWriteLock里锁的实现是靠java.util.concurrent.locks.ReentrantReadWriteLock.Sync完成的.这个类看起来比较眼熟,实际上它是AQS的一个子类,这中类似的结构在CountDownLatch.ReentrantLock.Semapho