[英]Do I need to worry about an object being thread safe if it has no static fields?
我正在编写一个装饰器来实现缓存。 该对象将由我的DI容器注册为单例。 因为我知道我将对象注册为单例,所以表示我的缓存的字段不是静态的。 我不确定这是否是最佳做法,但我正竭尽全力避免锁定。 我的缓存被延迟初始化,并且一次仅运行一次就很昂贵/昂贵。 我的问题是我是否需要担心多个线程运行缓存初始化逻辑? 我的直觉告诉我“是的,我确实需要担心”,但是我听过其他开发人员说“如果不是静态的,则没有意义进行锁定”。
//SimpleInjector DI Container configuration
public static class Bootstrapper
{
public static void ConfigureContainer(Container container)
{
container.Register<IQueryHandler<GetFoos, Foo[]>, GetFoosHandler>(Lifestyle.Singleton);
container.RegisterDecorator<IQueryHandler<GetFoos, Foo[]>, GetFoosCachingHandler>(Lifestyle.Singleton);
}
}
public class Foo
{
public int Id;
public string FooTypeCode;
public string Name;
}
public class GetFoos : IQuery<Foo[]>
{
public string FooTypeCode;
}
public class GetFoosCachingHandler : IQueryHandler<GetFoos, Foo[]>
{
private Lazy<Dictionary<string, Foo[]>> _cache;
private readonly IQueryHandler<GetFoos, Foo[]> _queryHandler;
public GetFoosCachingHandler(IQueryHandler<GetFoos, Foo[]> queryHandler)
{
_queryHandler = queryHandler;
_cache = new Lazy<Dictionary<string, Foo[]>>(() =>
{
//expensive and run only once operation e.g. subscribe to bus for cache invalid messages and reset cache
return new Dictionary<string, Foo[]>();
});
}
public Foo[] Handle(GetFoos query)
{
var cache = _cache.Value;
if (!cache.ContainsKey(query.FooTypeCode))
{
cache[query.FooTypeCode] = _queryHandler.Handle(new GetFoos { FooTypeCode = query.FooTypeCode });
}
return cache[query.FooTypeCode];
}
}
是的,您需要锁定以防止多个线程运行相同的代码。
“如果不是静态的,则锁定没有意义”
仅当每个线程都有自己的类实例时才适用。 在线程之间共享实例后,就需要同步访问。
Guffa是对的。 此时无须补充。 我要添加的是一些重构。 您可能应该从装饰器中提取缓存行为,如下所示:
public class GetFoosCachingHandler : IQueryHandler<GetFoos, Foo[]>{
private readonly ICache _cache;
private readonly IQueryHandler<GetFoos, Foo[]> _queryHandler;
public GetFoosCachingHandler(ICache cache, IQueryHandler<GetFoos, Foo[]> queryHandler){
_cache = cache;
_queryHandler = queryHandler;
}
public Foo[] Handle(GetFoos query) {
var result = _cache.Load<Foo[]>(query.FooTypeCode);
if (result == null) {
_cache.Store<Foo[]>(query.FooTypeCode, result = _queryHandler.Handle(query));
}
return result;
}
}
这里需要注意的几件事:
Dictionary<,>
确实是轻量级的,并且总是创建字典。 Foo
和数组都是),这使得在多个线程上重用它们很危险(您永远都不知道谁会更改它们)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.