zoukankan      html  css  js  c++  java
  • Singleton模式与对象池的假设....

        最近在园子的首页经常会看到一些有关设计模式的文章。23种设计模式要完全掌握可不一件容易的事.最早了解的种设计模式是Singleton模式(单件模式),主要是因为它简单。套用别人的代码大概是这样子:

    public class Singleton
        
    {
            
    private static Singleton m_instance = new Singleton();
            
    public static Singleton Instance
            
    {
                
    get return m_instance; }
            }

            
    protected Singleton() { }
            
    public void WL(string p_strMsg)
            
    {
                Console.WriteLine(p_strMsg);
                Thread.Sleep(
    1000);
            }

        }
    上面简单的代码就实现了Singleton模式了。但今天在写代码的时候在有一个问题一直没能想明白。当在一个系统当中,同时有多个客户访问了这个对象,或者说对象当中的某一个方法。那对象能否同时为多个客户服务呢?还是要等待(类似于访问互斥资源的需要lock)?用下面的代码进行测试:
     1 class Program
     2    {
     3        static void Main(string[] args)
     4        {
     5            for (int i = 0; i < 100; i++)
     6            {
     7                Thread thread = new Thread(new ThreadStart(ThreadFunc));
     8                thread.Name = "Thread " + i.ToString();
     9                thread.Start();
    10            }

    11            RL();
    12        }

    13        public static void ThreadFunc()
    14        {
    15            for (int i = 0; i < 1000; i++)
    16            {
    17                Singleton.Instance.WL("Thread Name:" + Thread.CurrentThread.Name + " Count:" + i.ToString() + " Object HashCode:" + Singleton.Instance.GetHashCode().ToString());
    18                //Thread.Sleep(300);
    19            }

    20        }
            
    21        private static void RL()
    22        {
    23            Console.ReadLine();
    24        }

    25
    26    }

    从宏观上看,一个对象被一个客户占有,至少在执行一个原子函数时,应该是不能被别外一个客户使用的,而当这个原子函数的执行时间很长(网络超时)。那其它的客户不都要停止工作了?但从微观上,单CPU的计算机同时一时刻只能有一个作业在执进,而这时Singleton的对象又是怎么样被执行的?如果说它能随意地让每个客户共享的话,那在我们的项目中就不需要每次执行都去实例化对象,对相同的类在一个AppDomain只存在一个实例,这样就可以减少在实例化对象上的性能损耗和.NET 拖管堆的压力。而这种方案是否可行??执行上面的测试,结果是可行的,我创建了100线程,每个线程都执行了WL()方法,在方法里面让线程等待3秒,而在当这个线程等待时,另外一个线程还是可以工作的。
        有一种场景,在Provider模式中(.NET 2.0和CS经常用到的一种模式)的。在使用这些的Provider的时候,不可避免的都会遇到对象的实例化问题,用反射的方法进行实例化(Activator.CreateInstance(string p_strType),也分不清这种方法算不算反向技术?),如果每次使用都去实例化,从理论上都会对性能造成一定的影响。而今天在考虑这个问题的时候首先想到的就是用Singleton模式,还有一种方法叫对象池?记得在看《.NET框架程序设计》的时候提到了对象的生命周期和对象池方法。
        忘了怎么样在书里面是怎么样去实现对象池了。不过目前有一个想法就是用IDisposable这个接口来做文章。所有的对象都继承这个类,然后实现Dispose方法,这个方法不去Dispose对象,只是将对象的Used标志记成false,然后放回池里面:
    public interface IPoolDispose : IDisposable
       
    {
            
    bool Used get;set;}
        }

    对象定义如下:
     public class ObjectPool : IPoolDispose
        {
            private int m_intUsed = 0;
            public void WL()
            {
                m_intUsed++;
                Console.WriteLine(this.GetHashCode() + "我被使用了: " + m_intUsed.ToString() + "次");
                Thread.Sleep(30);            //对象等待时间
            }
            private bool m_bUsed = false;
            public bool Used
            {
                get { return m_bUsed; }
                set { m_bUsed = value; }
            }
            public void Dispose()
            {
                Used = false;
            }
        }
    至于缓存,我想可以放在一个静态的ArrayList,或者将ArrayList缓存缓存中。这边还需要一个类工厂负责创建并返回类实例:
    public class ClassFactory
        {
            static ArrayList array = new ArrayList();
            public static ObjectPool CreateObject()
            {
                foreach (IPoolDispose pool in array)
                {
                    if (pool.Used == false)
                    {
                        pool.Used = true;
                        return (ObjectPool)pool;
                    }
                }
                ObjectPool m_object = new ObjectPool();
                if (array.Count < 10)
                    array.Add(m_object);
                return m_object;
            }
        }
    用下面的代码运行测试:
     class Program
        
    {
            
    static void Main(string[] args)
            
    {
                
    for (int i = 0; i < 100; i++)
                
    {
                    Thread thread 
    = new Thread(new ThreadStart(ThreadFunc2));
                    thread.Name 
    = "Thread " + i.ToString();
                    thread.Start();
                }

                RL();
                
            }

           
            
    public static void ThreadFunc2()
            
    {
                ObjectPool m_objectPool 
    = ClassFactory.CreateObject();
                
    using (m_objectPool)
                
    {
                    m_objectPool.WL();
                }

            }

            
    private static void RL()
            
    {
                Console.ReadLine();
            }


        }
    会发现,如果上面的对象等待时间设得比较长的话,就会创建很多对象,而且很多对象都只使用了一次。而如果设置得很短的话,比如0。就类似于Singleton模式了,一百个线程都使用一个实例,这个实例就被使用了100次。
        以上两种方法都可以实现对象的复用,减少对象的实例次数?Singleton甚至只需要实例一次。而这两种方法有什么不一样的地方,各自的优缺点都在哪里呢?有可能给系统带来什么样的影响呢?
    源码: 下载
  • 相关阅读:
    桟错误分析方法
    gstreamer调试命令
    sqlite的事务和锁,很透彻的讲解 【转】
    严重: Exception starting filter struts2 java.lang.NullPointerException (转载)
    eclipse 快捷键
    POJ 1099 Square Ice
    HDU 1013 Digital Roots
    HDU 1087 Super Jumping! Jumping! Jumping!(动态规划)
    HDU 1159 Common Subsequence
    HDU 1069 Monkey and Banana(动态规划)
  • 原文地址:https://www.cnblogs.com/hjf1223/p/266750.html
Copyright © 2011-2022 走看看