1

对不起,如果这已经在其他地方得到了回答……我发现了很多关于类似事情的帖子,但不一样。

我想确保一次只存在一个对象的一个​​实例,但我不希望该对象在其自然生命周期之后保留,因为它可能是单例模式。

我正在编写一些代码,其中每分钟都会触发列表处理(由我无法控制的外部代码)。目前,我每次只创建一个新的“处理”对象,当它超出范围时,它会按照正常情况被销毁。但是,有时处理时间可能超过一分钟,因此下一个触发器将在新线程中创建处理类的第二个实例。

现在,我想要一种机制,一次只能存在一个实例……比如说,某种工厂一次只允许一个对象。例如,对工厂的第二次调用将返回 null,而不是一个新对象。

到目前为止,我的(蹩脚的)解决方案是将工厂类型对象作为处理器类的嵌套类:

class XmlJobListProcessor
{
    private static volatile bool instanceExists = false;

    public static class SingletonFactory
    {
        private static object lockObj = new object();

        public static XmlJobListProcessor CreateListProcessor()
        {
            if (!instanceExists)
            {
                lock (lockObj)
                {
                    if (!instanceExists)
                    {
                        instanceExists = true;
                        return new XmlJobListProcessor();
                    }
                    return null;
                }
            }
            return null;
        }
    }

    private XmlJobListProcessor() { }
    ....
    }

我正在考虑为 XmlJobListProcessor 类编写一个显式析构函数,将“instanceExists”字段重置为 false。

我意识到这是一个非常糟糕的设计。工厂本身应该是一个类...它只是嵌套的,因此它和实例析构函数都可以访问 volatile 布尔值...

有人有更好的方法来做到这一点吗?干杯

4

5 回答 5

2

我知道 .NET 4 没有被广泛使用,但最终它会被广泛使用,并且您将拥有:

private static readonly Lazy<XmlJobListProcessor> _instance =
    new Lazy<XmlJobListProcessor>(() => new XmlJobListProcessor());

然后你可以通过 访问它_instance.Value,它在第一次被请求时被初始化。

于 2010-02-01T03:23:20.983 回答
1

您的原始示例使用双重检查锁定,应不惜一切代价避免。

请参阅msdn Singleton implementation,了解如何正确初始化 Singleton。

于 2010-02-01T03:20:07.020 回答
0

我接受每个人关于不重新实例化处理器对象的观点和 BillW 关于队列的观点,所以这是我的混搭混搭解决方案:

public static class PRManager
{
    private static XmlJobListProcessor instance = new XmlJobListProcessor();
    private static object lockobj = new object();

    public static void ProcessList(SPList list)
    {
         bool acquired = Monitor.TryEnter(lockobj);
            try
            {
                if (acquired)
                {
                    instance.ProcessList(list);
                }
            }
            catch (ArgumentNullException)
            {
            }
            finally
            {
                Monitor.Exit(lockobj);
            }
    }
}

处理器作为静态成员长期保留(这里,长期对象保留不是问题,因为它没有状态变量等)如果在 lockObj 上获得了锁,则不会处理请求并且调用线程将继续其业务。

为反馈的家伙干杯。Stackoverflow 将确保我的实习!;D

于 2010-02-01T03:14:28.067 回答
0

只制作一个并保留它,不要每分钟破坏和创造它

“最小化运动部件”

于 2010-02-01T00:45:22.580 回答
0

我会实例化该类并保留它。当然,我不会使用析构函数(如果你的意思是 ~myInstance() )......这会增加 GC 时间。此外,如果一个过程花费的时间超过一分钟,如果您只返回一个空值,您将如何处理假设要处理的数据?

保持实例处于活动状态,并可能构建一个缓冲区机制以在处理器类忙时继续接收输入。你可以检查看看:

if ( isBusy == true )
{
     // add data to bottom of buffer
}
else
{
     // call processing
}
于 2010-02-01T01:15:59.803 回答