• 对象池的设计


    对象池的设计及其实现

    对象池概述:

    对象池模型创建并拥有固定数量的对象,当程序需要一个新的对象时,如果对象池中有空闲对象,则立即返回,否则才创建新的该类对象。当一个对象不再被使用时,其应该应该将其放回对象池,以便后来的程序使用。由于系统资源有限,一个对象池模型应该指定其可容纳的最大对象数量。当达到该数量时,如果仍然有对象创建请求,则抛出异常或者阻塞当前调用线程,直到一个对象被放回对象池中。

    对象池模型适用的场景:

    (1)需要使用大量对象

    (2)这些对象的实例化开销比较大且生存期比较短

    对象池优势:

    一个对象池可以在可容忍时间内创建成功并投入使用。但是创建对象时并不总是这样,尤其是当这些对象的创建过程比较耗时,而且创建和销毁频率又比较大时更是如此。比如数据库连接、网络套接字连接、线程对象、诸如字体或位图等图像对象等。

    实现:

    假设有如下类定义:

    复制代码
     1 class Object
     2 {
     3 public:
     4     Object(const string& name) : name_(name)
     5     {
     6         printf("Construct Object[%p] %s.
    ", this, name_.c_str());
     7     }
     8 
     9     ~Object()
    10     {
    11         printf("~Destruct Object[%p] %s.
    ", this, name_.c_str());
    12     }
    13 
    14     const string& key() const { return name_; }
    15 
    16 private:
    17     string name_;
    18 };
    复制代码

    如下对象池类的设计,用来提供Object类对象,分为2个版本介绍:(注意,如下仅考虑了对象池本身所涉及的特性,没有涉及同步控制机制)

    版本1

    复制代码
     1 class ObjectPool
     2 {
     3 public:
     4     boost::shared_ptr<Object> get(const string& key)
     5     {
     6         boost::shared_ptr<Object> pObject;
     7         boost::weak_ptr<Object>& k_object = objects_[key];
     8         pObject = k_object.lock();
     9         if (!pObject)
    10         {
    11             pObject.reset(new Object(key),
    12                          boost::bind(&ObjectPool::releaseObject, this, _1));
    13             k_object = pObject;
    14         }
    15         return pObject;
    16   }
    17 
    18 private:
    19     void releaseObject(Object* object)
    20     {
    21         printf("releaseObject[%p].
    ", object);
    22         if (object)
    23         {
    24             objects_.erase(object->key());
    25         }
    26         delete object;
    27     }
    28 
    29     std::map<string, boost::weak_ptr<Object> > objects_;
    30 };
    复制代码

    ObjectPool的get函数返回map中key对应的Object对象。如果该对象不存在,则新建一个Object,将其放入map中,然后返回这个新建的Object。同时,重置shared_ptr(新增Object对象)时指定析构器releaseObject,使得对象析构时执行releaseObject(object);

    但是上述实现存在一个问题:将this传入bind函数中,如果ObjectPool对象先于Object对象析构了,那么在析构Object对象时,如何调用releaseObject函数呢?(因为releaseObject函数属于ObjectPool类)

    版本2

    复制代码
     1 class ObjectPool : public boost::enable_shared_from_this<ObjectPool>
     2 {
     3 public:
     4     boost::shared_ptr<Object> get(const string& key)
     5     {
     6         boost::shared_ptr<Object> pObject;
     7         boost::weak_ptr<Object>& k_object = objects_[key];
     8         pObject = k_object.lock();
     9         if (!pObject)
    10         {
    11             pObject.reset(new Object(key),
    12                          boost::bind(&ObjectPool::releaseObject, shared_from_this(), _1));
    13             k_object = pObject;
    14         }
    15         return pObject;
    16   }
    17 
    18 private:
    19     void releaseObject(Object* object)
    20     {
    21         printf("releaseObject[%p].
    ", object);
    22         if (object)
    23         {
    24             objects_.erase(object->key());
    25         }
    26         delete object;
    27     }
    28 
    29     std::map<string, boost::weak_ptr<Object> > objects_;
    30 };
    复制代码

    要解决版本1中的问题,只需增加ObjectPool的寿命就可以了。可以利用boost::enable_shared_from_this模板类中的shared_from_this(),如此可以将this转换为shared_ptr<ObjectPool>。如此,由于bind是值传递语义,因此其必然保存一份shared_ptr<ObjectPool>的副本,可以保证shared_ptr的引用计数不为0。

    测试用例: 

    // object_pool.cc
    #include <map>

    #include <boost/bind.hpp>
    #include <boost/enable_shared_from_this.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/weak_ptr.hpp>

    #include <stdio.h>

    using std::string;
    const int MAXNUM = 5; // the largest amounts of objects
    int nums = 0; // the current amounts of objects

    class Object
    {
    public:
    Object(const string& name) : name_(name)
    {
    printf("Construct Object[%p] %s. ", this, name_.c_str());
    }

    ~Object()
    {
    printf("~Destruct Object[%p] %s. ", this, name_.c_str());
    }

    const string& key() const { return name_; }

    private:
    string name_;
    };


    namespace version1
    {

    class ObjectPool
    {
    public:
    boost::shared_ptr<Object> get(const string& key)
    {
    boost::shared_ptr<Object> pObject;
    boost::weak_ptr<Object>& k_object = objects_[key];
    pObject = k_object.lock();
    if (!pObject)
    {
    ++nums;
    BOOST_ASSERT(nums <= MAXNUM);
    pObject.reset(new Object(key),
    boost::bind(&ObjectPool::releaseObject, this, _1));
    k_object = pObject;
    }
    return pObject;
    }

    private:
    void releaseObject(Object* object)
    {
    printf("releaseObject[%p]. ", object);
    if (object)
    {
    --nums;
    objects_.erase(object->key());
    }
    delete object;
    }

    std::map<string, boost::weak_ptr<Object> > objects_;
    };

    }

    namespace version2
    {

    class ObjectPool : public boost::enable_shared_from_this<ObjectPool>
    {
    public:
    boost::shared_ptr<Object> get(const string& key)
    {
    boost::shared_ptr<Object> pObject;
    boost::weak_ptr<Object>& k_object = objects_[key];
    pObject = k_object.lock();
    if (!pObject)
    {
    ++nums;
    BOOST_ASSERT(nums <= MAXNUM);
    pObject.reset(new Object(key),
    boost::bind(&ObjectPool::releaseObject, shared_from_this(), _1));
    k_object = pObject;
    }
    return pObject;
    }

    private:
    void releaseObject(Object* object)
    {
    printf("releaseObject[%p]. ", object);
    if (object)
    {
    --nums;
    objects_.erase(object->key());
    }
    delete object;
    }

    std::map<string, boost::weak_ptr<Object> > objects_;
    };

    }


    int main()
    {
    boost::shared_ptr<version1::ObjectPool> op1(new version1::ObjectPool);

    boost::shared_ptr<Object> object1 = op1->get("object1");
    boost::shared_ptr<Object> object2 = op1->get("object2");
    boost::shared_ptr<Object> object3 = op1->get("object3");
    boost::shared_ptr<Object> object4 = op1->get("object4");
    boost::shared_ptr<Object> object5 = op1->get("object5");
    boost::shared_ptr<Object> object6 = op1->get("object5");

    //boost::shared_ptr<version2::ObjectPool> op2(new version2::ObjectPool);
    //boost::shared_ptr<Object> object7 = op2->get("object2");
    //boost::shared_ptr<Object> object8 = op2->get("object2");

    return 0;
    }

    // output
    Construct Object[003e1060] object1.
    Construct Object[003e10e0] object2.
    Construct Object[003e1160] object3.
    Construct Object[003e11e0] object4.
    Construct Object[003e1260] object5.
    releaseObject[003e1260].
    ~Destruct Object[003e1260] object5.
    releaseObject[003e11e0].
    ~Destruct Object[003e11e0] object4.
    releaseObject[003e1160].
    ~Destruct Object[003e1160] object3.
    releaseObject[003e10e0].
    ~Destruct Object[003e10e0] object2.
    releaseObject[003e1060].
    ~Destruct Object[003e1060] object1.

    复制代码
      1 // object_pool.cc
      2 #include <map>
      3 
      4 #include <boost/bind.hpp>
      5 #include <boost/enable_shared_from_this.hpp>
      6 #include <boost/shared_ptr.hpp>
      7 #include <boost/weak_ptr.hpp>
      8 
      9 #include <stdio.h>
     10 
     11 using std::string;
     12 const int MAXNUM = 5;  // the largest amounts of objects
     13 int nums = 0;          // the current amounts of objects
     14 
     15 class Object
     16 {
     17 public:
     18     Object(const string& name) : name_(name)
     19     {
     20         printf("Construct Object[%p] %s.
    ", this, name_.c_str());
     21     }
     22 
     23     ~Object()
     24     {
     25         printf("~Destruct Object[%p] %s.
    ", this, name_.c_str());
     26     }
     27 
     28     const string& key() const { return name_; }
     29 
     30 private:
     31     string name_;
     32 };
     33 
     34 
     35 namespace version1
     36 {
     37 
     38 class ObjectPool
     39 {
     40 public:
     41     boost::shared_ptr<Object> get(const string& key)
     42     {
     43         boost::shared_ptr<Object> pObject;
     44         boost::weak_ptr<Object>& k_object = objects_[key];
     45         pObject = k_object.lock();
     46         if (!pObject)
     47         {
     48             ++nums;
     49             BOOST_ASSERT(nums <= MAXNUM);
     50             pObject.reset(new Object(key),
     51                          boost::bind(&ObjectPool::releaseObject, this, _1));
     52             k_object = pObject;
     53         }
     54         return pObject;
     55   }
     56 
     57 private:
     58     void releaseObject(Object* object)
     59     {
     60         printf("releaseObject[%p].
    ", object);
     61         if (object)
     62         {
     63             --nums;
     64             objects_.erase(object->key());
     65         }
     66         delete object;
     67     }
     68 
     69     std::map<string, boost::weak_ptr<Object> > objects_;
     70 };
     71 
     72 }
     73 
     74 namespace version2
     75 {
     76 
     77 class ObjectPool : public boost::enable_shared_from_this<ObjectPool>
     78 {
     79 public:
     80     boost::shared_ptr<Object> get(const string& key)
     81     {
     82         boost::shared_ptr<Object> pObject;
     83         boost::weak_ptr<Object>& k_object = objects_[key];
     84         pObject = k_object.lock();
     85         if (!pObject)
     86         {
     87             ++nums;
     88             BOOST_ASSERT(nums <= MAXNUM);
     89             pObject.reset(new Object(key),
     90                          boost::bind(&ObjectPool::releaseObject, shared_from_this(), _1));
     91             k_object = pObject;
     92         }
     93         return pObject;
     94   }
     95 
     96 private:
     97     void releaseObject(Object* object)
     98     {
     99         printf("releaseObject[%p].
    ", object);
    100         if (object)
    101         {
    102             --nums;
    103             objects_.erase(object->key());
    104         }
    105         delete object;
    106     }
    107 
    108     std::map<string, boost::weak_ptr<Object> > objects_;
    109 };
    110 
    111 }
    112 
    113 
    114 int main()
    115 {
    116     boost::shared_ptr<version1::ObjectPool> op1(new version1::ObjectPool);
    117 
    118     boost::shared_ptr<Object> object1 = op1->get("object1");
    119     boost::shared_ptr<Object> object2 = op1->get("object2");
    120     boost::shared_ptr<Object> object3 = op1->get("object3");
    121     boost::shared_ptr<Object> object4 = op1->get("object4");
    122     boost::shared_ptr<Object> object5 = op1->get("object5");
    123     boost::shared_ptr<Object> object6 = op1->get("object5");
    124 
    125     //boost::shared_ptr<version2::ObjectPool> op2(new version2::ObjectPool);
    126     //boost::shared_ptr<Object> object7 = op2->get("object2");
    127     //boost::shared_ptr<Object> object8 = op2->get("object2");
    128 
    129     return 0;
    130 }
    131 
    132 // output
    133 Construct Object[003e1060] object1.
    134 Construct Object[003e10e0] object2.
    135 Construct Object[003e1160] object3.
    136 Construct Object[003e11e0] object4.
    137 Construct Object[003e1260] object5.
    138 releaseObject[003e1260].
    139 ~Destruct Object[003e1260] object5.
    140 releaseObject[003e11e0].
    141 ~Destruct Object[003e11e0] object4.
    142 releaseObject[003e1160].
    143 ~Destruct Object[003e1160] object3.
    144 releaseObject[003e10e0].
    145 ~Destruct Object[003e10e0] object2.
    146 releaseObject[003e1060].
    147 ~Destruct Object[003e1060] object1.
    复制代码

    References

    https://en.wikipedia.org/wiki/Object_pool_pattern

  • 相关阅读:
    springmvc入门详解
    getClass 与getSimpleName
    mybati的存储过程
    mybatis与spring的整合
    mybatis分页插件以及懒加载
    mybatis知识总结
    【Java面试题】30 子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。
    【Java面试题】29 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。
    【Java面试题】28 简述synchronized和java.util.concurrent.locks.Lock的异同 ?
    【Java面试题】27 多线程笔试面试概念问答
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4870439.html
Copyright © 2020-2023  润新知