类设计
using System;
using System.Collections.Generic;
using System.Threading;
public class ThreadSafeClass
{
private readonly object _lockObject = new object();
private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
private int _propertyValue;
private Dictionary<int, string> _indexerData = new Dictionary<int, string>();
// 线程安全的属性
public int Property
{
get
{
_rwLock.EnterReadLock();
try
{
return _propertyValue;
}
finally
{
_rwLock.ExitReadLock();
}
}
set
{
_rwLock.EnterWriteLock();
try
{
_propertyValue = value;
}
finally
{
_rwLock.ExitWriteLock();
}
}
}
// 线程安全的索引器
public string this[int index]
{
get
{
_rwLock.EnterReadLock();
try
{
if (_indexerData.ContainsKey(index))
{
return _indexerData[index];
}
return null;
}
finally
{
_rwLock.ExitReadLock();
}
}
set
{
_rwLock.EnterWriteLock();
try
{
if (_indexerData.ContainsKey(index))
{
_indexerData[index] = value;
}
else
{
_indexerData.Add(index, value);
}
}
finally
{
_rwLock.ExitWriteLock();
}
}
}
}
同步机制
- 读写锁(ReaderWriterLockSlim):对于属性的读取和索引器的读取操作,使用读锁(EnterReadLock),允许多个线程同时读取数据,提高并发性能。对于属性的写入和索引器的写入操作,使用写锁(EnterWriteLock),只允许一个线程进行写入,保证数据一致性。
- 对象锁(object):在需要更粗粒度的同步时,可以使用
object
锁。但在本示例中,由于读写锁已经能满足需求,object
锁未被直接使用,只是作为一个示例存在。
避免死锁
- 锁获取顺序一致:确保在整个应用程序中,线程获取锁的顺序是一致的。例如,如果一个线程先获取
_rwLock
的写锁,再获取其他锁,那么其他线程也应该按照相同的顺序获取锁。
- 超时机制:
ReaderWriterLockSlim
提供了带有超时参数的锁获取方法,如EnterReadLock(int millisecondsTimeout)
和EnterWriteLock(int millisecondsTimeout)
。可以设置合理的超时时间,避免线程无限期等待锁,从而防止死锁。
性能优化
- 锁的粒度控制:使用
ReaderWriterLockSlim
而不是简单的lock
关键字,减小锁的粒度。读操作可以并发执行,只有写操作才需要独占锁,提高了并发性能。
- 读写锁的应用场景:适用于读多写少的场景,如缓存系统。在这种场景下,大量的读操作可以并发执行,只有少量的写操作需要独占锁,从而提高系统的整体性能。