在我的Web应用程序中,我对所有在线用户都有以下通用的objectList.
public static List<MyClass> myObjectList = new List<MyClass>();
因此,当多个在线用户尝试从此对象myObjectList读取数据时,就有可能发生线程同步问题.
在另一种情况下,多个用户正在从myObjectList进行读取,而其中很少有人也在写入,但是每个用户都在List的不同索引上进行写入.每个用户都可以在此列表中添加一个新项目.所以现在我认为有同步问题的机会.
如何编写线程安全实用程序类,该类可以以更安全的方式从该对象读取和写入数据.
非常欢迎提出建议
Angelo建议的代码如下所示
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace ObjectPoolExample
{
public class ObjectPool<T>
{
private ConcurrentBag<T> _objects;
private Func<T> _objectGenerator;
public ObjectPool(Func<T> objectGenerator)
{
if (objectGenerator == null) throw new ArgumentNullException("objectGenerator");
_objects = new ConcurrentBag<T>();
_objectGenerator = objectGenerator;
}
public T GetObject()
{
T item;
if (_objects.TryTake(out item)) return item;
return _objectGenerator();
}
public void PutObject(T item)
{
_objects.Add(item);
}
}
class Program
{
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
// Create an opportunity for the user to cancel.
Task.Factory.StartNew(() =>
{
if (Console.ReadKey().KeyChar == 'c' || Console.ReadKey().KeyChar == 'C')
cts.Cancel();
});
ObjectPool<MyClass> pool = new ObjectPool<MyClass> (() => new MyClass());
// Create a high demand for MyClass objects.
Parallel.For(0, 1000000, (i, loopState) =>
{
MyClass mc = pool.GetObject();
Console.CursorLeft = 0;
// This is the bottleneck in our application. All threads in this loop
// must serialize their access to the static Console class.
Console.WriteLine("{0:####.####}", mc.GetValue(i));
pool.PutObject(mc);
if (cts.Token.IsCancellationRequested)
loopState.Stop();
});
Console.WriteLine("Press the Enter key to exit.");
Console.ReadLine();
}
}
// A toy class that requires some resources to create.
// You can experiment here to measure the performance of the
// object pool vs. ordinary instantiation.
class MyClass
{
public int[] Nums {get; set;}
public double GetValue(long i)
{
return Math.Sqrt(Nums[i]);
}
public MyClass()
{
Nums = new int[1000000];
Random rand = new Random();
for (int i = 0; i < Nums.Length; i++)
Nums[i] = rand.Next();
}
}
}
我想我可以采用这种方法.
解决方法:
如果您使用的是.NET 4.0,最好更改为运行时已支持的thread-safe collections之一,例如ConcurrentBag
.
但是,如果我没记错的话,并发包不支持按索引访问,因此,如果需要通过给定键访问对象,则可能需要求助于ConcurrentDictionary
.
如果不能使用.NET 4.0,则应阅读以下博客文章:
Why are thread safe collections so hard?