阿不

潜水

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

    最近在园子的首页经常会看到一些有关设计模式的文章。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甚至只需要实例一次。而这两种方法有什么不一样的地方,各自的优缺点都在哪里呢?有可能给系统带来什么样的影响呢?
源码: 下载
posted on 2005-11-01 23:58  阿不  阅读(2409)  评论(5编辑  收藏  举报