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甚至只需要实例一次。而这两种方法有什么不一样的地方,各自的优缺点都在哪里呢?有可能给系统带来什么样的影响呢?
    源码: 下载
  • 相关阅读:
    2022北航软件研究生入学考试991考试大纲-数据结构与C
    pgsql 学习
    Java开发必须掌握的 20+ 种 Spring 常用注解
    Spring 学习总结
    Spring MVC快速入门教程
    spring boot与spring mvc的区别是什么?
    Java知识体系最强总结(2020版)
    arthas(阿尔萨斯)使用实践----查看慢方法 /方法耗时等
    JVM --------jmap-----查看堆内存信息、生成heap dump 文件(转储堆内存快照到指定文件)
    [JVM】jstat命令详解---JVM的统计监测工具:jstat 堆内存各部分的使用量,以及加载类的数量。
  • 原文地址:https://www.cnblogs.com/hjf1223/p/266750.html
Copyright © 2011-2022 走看看