我想确保我总是只创建一个Thread的一个实例,所以我构建了这个:
private static volatile Thread mdmFetchThread = null;
private static object Locker = new object();
public void myMethod(){
string someParameter = getParameterDynamically();
lock(Locker)
{
// If an mdmFetchThread is already running, we do not start a new one.
if(mdmFetchThread != null && mdmFetchThread.ThreadState != ThreadState.Stopped)
{
// warn...
}
else
{
mdmFetchThread = new Thread(() => { doStuff(someParameter); });
mdmFetchThread.Start();
}
}
}
这样做可行或可能存在哪些陷阱?
//编辑:根据请求下面的位上下文:doStuff()
正在调用某个外部系统。此调用可能会超时,但我无法指定超时。所以我在mdmFetchThread
中调用它并稍后执行mdmFetchThread.join(20000)
。为了避免我两次调用外部系统,我创建了静态变量,以便我可以检查当前是否正在进行呼叫。
答案 0 :(得分:3)
将线程存储在静态变量中是正常的(如果每个AppDomain最多需要一个这样的线程)。您可以在静态存储中存储任何内容。
条件mdmFetchThread.ThreadState != ThreadState.Stopped
很活泼。在线程退出之前,您可能会发现它为1纳秒。然后你不小心无所事事。保持自己的布尔状态变量并正确同步。放弃volatile
,因为它比必要的更复杂。
考虑切换到Task
。它更现代。减少陷阱。
考虑使用Lazy<Task>
创建所需的单例行为。
添加错误处理。后台线程中的崩溃会终止进程,而不会通知开发人员错误。
答案 1 :(得分:0)
一般来说,如果您使用静态来存储状态(例如线程),那么在尝试向外扩展或尝试管理对象的生命周期时,您可能会遇到设计缺陷。我通常尽可能避免使用静力学。
另一种方法可能是创建一个只管理单个线程的类来执行作为实例的任务。此类可能负责将数据传递给您的线程或管理它的状态。例如,确保它只运行一次,正常停止线程,或者在线程完成时进行处理。如果你想扩展,那么你只需创建你的类的多个实例,每个实例都有自己管理的线程。如果你只想要一个,那么只需传递一个实例。
如果您正在寻找使这个实例可用于整个应用程序的方法(这通常是人们在使用静态变量时试图解决的问题),那么请查看使用ServiceContainers和IServiceProvider等模式。