锁定与并发

简介: 在多线程程序中,我们经常需要对要访问的资源进行加锁。加锁的目的是为了同步对资源的访问,但是,加锁不可避免的会降低应用的并发量。那么如何在需要加锁的时候,尽可能地提高并发量了?下面是我的一些经验,仅供参考。

     在多线程程序中,我们经常需要对要访问的资源进行加锁。加锁的目的是为了同步对资源的访问,但是,加锁不可避免的会降低应用的并发量。那么如何在需要加锁的时候,尽可能地提高并发量了?下面是我的一些经验,仅供参考。

 1.首先,我们要控制好锁的粒度。

     锁的粒度越大,能支持的并发就越小。

     我们只需要将真正需要同步的代码块lock住,而不需要同步的代码块不要放在lock块中。

     当然,锁的粒度也不是越小越好,粒度太细的锁会导致编程很繁琐,而且需要足够的细心和全面考虑方可保证锁不会出现问题。

     在这点上,有一个特别需要注意的是 -- 事件。事件最好不要在lock块中触发,因为你无法确定组件应用者的事件处理函数会执行多久。除非,你对一切了然于胸。

             lock  ( this .locker)
            {
                
//

                
this .OnSomeEvent();  // 触发事件
            }

 

2.杜绝死锁的发生。当发生死锁时,并发将降到最低。

3.区分读写。

     我们经常使用lock关键字来锁定资源,然而,lock没有办法区分读写。比如,如果当前同时有三个线程在访问资源,且三个都是读取资源,如果使用lock,那么,在读取资源上,它们也会被同步处理。幸运的是,.NET为我们提供了读写锁 -- ReaderWriterLock ,使用它,上面的例子便是三个线程可以同时读取资源。

     对于那种读取多于修改的资源,区分读写可以极大地提升并发量。

     ReaderWriterLock的使用不如lock来得方便,为此,我封装了SmartRWLocker,它提供了和ReaderWriterLock一样的功能,但是我们可以像使用lock一样来使用它,如: 

            using ( this .smartRWLocker.Lock(AccessMode.Read))
            {
                
// do something
            }

     SmartRWLocker的实现也相当简单,如下所示:

     /// <summary>
    
/// SmartRWLocker 简化了ReaderWriterLock的使用。zhuweisky 2008.11.25
    
/// </summary>
    public class SmartRWLocker
    {
        
private ReaderWriterLock readerWriterLock = new ReaderWriterLock();

        
public LockingObject Lock(AccessMode accessMode)
        {
            
return new LockingObject(this.readerWriterLock, accessMode);
        }
    }   

    
/// <summary>
    
/// AccessMode 访问锁定资源的方式。
    
/// </summary>
    public enum AccessMode
    {       
        Read 
= 0,
        Write
    }

public   class  LockingObject : IDisposable
    {
        
private  ReaderWriterLock readerWriterLock;
        
private  AccessMode accessMode  =  AccessMode.Read;

        
#region  Ctor
        
public  LockingObject(ReaderWriterLock _lock, AccessMode _lockMode)
        {
            
this .readerWriterLock  =  _lock;
            
this .accessMode  =  _lockMode;

            
if  ( this .accessMode  ==  AccessMode.Read)
            {
                
this .readerWriterLock.AcquireReaderLock( - 1 );
            }
            
else
            {
                
this .readerWriterLock.AcquireWriterLock( - 1 );
            }
        }
        
#endregion

        
#region  IDisposable 成员

        
public   void  Dispose()
        {
            
if  ( this .accessMode  ==  AccessMode.Read)
            {
                
this .readerWriterLock.ReleaseReaderLock();
            }
            
else
            {
                
this .readerWriterLock.ReleaseWriterLock();
            }
        }
        
#endregion
    }

 

 

 2009.02.23 附加:

     我们都知道,对于集合类,如Lits<>,Dictionary<,>等,

(1)如果其它线程在对其中的元素进行修改(如添加或删除元素)时,正在对集合进行枚举的线程会抛出异常。

(2)如果有一个线程正在对集合进行修改,另外一个线程调用Contains/ContainsKey,会抛出异常吗?答案是不会

 

 

 

 

目录
相关文章
|
6月前
|
缓存 数据库
并发修改同一记录时需要加锁
并发修改同一记录时需要加锁
|
6月前
|
消息中间件 缓存 监控
中间件锁定和并发问题
中间件锁定是一种机制,用于在并发访问时保护共享资源或数据。通过锁定,可以确保在给定时间内只有一个用户或线程能够访问或修改特定资源。
59 4
|
6月前
|
数据库连接 数据库
多线程事务失效的原因
【5月更文挑战第16天】多线程事务失效的原因
372 0
|
6月前
|
Java 调度 C++
多线程之常见的锁策略
多线程之常见的锁策略
|
12月前
|
安全
服务器被锁定
服务器被锁定
178 0
|
设计模式
【并发技术04】线程技术之死锁问题
【并发技术04】线程技术之死锁问题
|
安全 Java 程序员
多线程(八):常见锁策略
多线程(八):常见锁策略
186 0
多线程(八):常见锁策略
|
安全 Java 调度
认识并发中常见的锁
1. 锁的作用 2. 乐观锁和悲观锁 1)乐观锁 2)悲观锁 3)乐观锁和悲观锁在 Java 中的典型实现 4)数据版本机制 3. CAS 机制 1)什么是 CAS 2)CAS 的 ABA 问题 4. 读写锁 1)Java 标准库中提供的读写锁 5. 偏向锁、轻量级锁和重量级锁 1)偏向锁 2)轻量级锁 3)重量级锁 6. 自旋锁 7. 公平锁和非公平锁
115 0
|
安全 Java 调度
多线程常见的锁策略
多线程常见的锁策略
98 0
并发锁(一):为什么要加锁
并发锁(一):为什么要加锁
160 0
并发锁(一):为什么要加锁