自定義對象池實踐

自從研究了 commons-pool2 之後,進行了多次實踐,實現的效果也是非常好的。但是在一些輕量級場景當中,使用 commons-pool2 着實有點大材小用。

在某一次嘗試自定義的池化技術開發,優化服務內存的實踐當中,實在是忍無可忍,就動手自己寫了一個簡單的池化工具類。

思路

首先在簡單場景中,就是針對某一類對象,進行對象的緩存。思路基本沿用了 commons-pool2 的設計思路。

  1. 使用隊列儲存緩存對象
  2. 對外提供借出對象、歸還對象方法。
  3. 提供緩存大小、控制緩存數量API,但不強制。

本次實踐以簡單爲原則,已之前分享過的Go語言的對象池化中用到的 sync.Pool 工具類爲基礎,使用到的對象參考使用 commons-pool2

代碼

下面是我的第一版代碼:

package com.funtester.funpool

import java.util.concurrent.LinkedBlockingQueue

/**
 * Object pool, using LinkedBlockingQueue to store objects, and using factory to create new objects, and using offer to return objects, and using poll to borrow objects, and using trimQueue to trim queue size
 * @param <F>
 */
class FunPool<F> {

    /**
     * Factory to create new objects
     */
    FunPooledFactory<F> factory

    /**
     * Object pool, using LinkedBlockingQueue to store objects
     */
    LinkedBlockingQueue<F> pool = new LinkedBlockingQueue<F>()

    FunPool(FunPooledFactory<F> factory) {
        this.factory = factory
    }

    /**
     * Borrow an object from the pool
     *
     * @param o the object to be borrowed
     * @return
     */
    F borrow() {
        F f = pool.poll()
        if (f == null) {
            f = factory.newInstance()
        }
        return f
    }

    /**
     * Return the object to the pool
     *
     * @param f the object to be returned
     */
    def back(F f) {
        boolean offer = pool.offer(f)
        if (!offer) f = null
    }

    /**
     * return size of object pool
     *
     * @return
     */
    int size() {
        return pool.size()
    }


    /**
     * Trim the queue size
     * @param size the size to be trimmed
     */
    def trimQueue(int size) {
        while (true) {
            if (size() <= size) break
            pool.poll()
        }
    }


}

下面是工廠類的接口:

package com.funtester.funpool  
  
/**  
 * Factory to create new objects * @param <F>  
 */interface FunPooledFactory<F> {  
  
    /**  
     * Create new objects     * @return  
     */  
    F newInstance()  
  
}

代碼解讀:

這段代碼實現了一個對象池(Object Pool)的核心功能,可以在需要時從池中獲取對象,並在不需要時將對象返回池中以供重複利用。讓我們更詳細地瞭解其中的一些關鍵點:

  1. 對象池設計思路: 對象池是一種常見的設計模式,旨在通過預先創建和緩存對象來提高系統的性能和資源利用率。在高併發或頻繁創建銷燬對象的場景下,對象池可以顯著減少對象的創建和銷燬開銷。
  2. 工廠模式: 在這段代碼中,使用了工廠模式來創建新的對象。通過 FunPooledFactory 接口及其實現類,可以靈活地創建不同類型的對象,並將其納入對象池的管理之中。
  3. 線程安全性: 使用了 LinkedBlockingQueue 作爲對象池的存儲容器,這是一個線程安全的隊列實現。這意味着即使在多線程環境下,對象的借用和歸還操作也能夠保證線程安全。
  4. 對象借用與歸還: borrow() 方法用於從對象池中借用對象,它首先嚐試從隊列中取出一個對象,如果隊列爲空,則通過工廠創建一個新對象,並返回。而 back() 方法則用於將對象歸還到對象池中,它嘗試將對象放入隊列中,如果隊列已滿,則丟棄該對象。
  5. 隊列大小控制: trimQueue() 方法用於調整隊列的大小,使其不超過指定的大小。這樣可以避免對象池佔用過多的內存資源,同時保證對象池的性能和效率。

這段代碼實現了一個簡單但功能完備的對象池,可以用於管理和複用對象,提高系統的性能和資源利用率。

測試

測試腳本如下:

static void main(String[] args) {  
    def pool = new FunPool<Demo>(new FunPooledFactory<Demo>() {//創建一個對象池  
  
        @Override  
        Demo newInstance() {//創建一個新的對象  
            return new Demo()  
        }  
    })  
    def first = pool.borrow()//從對象池中借一個對象  
    println first.hashCode()//打印對象的hashcode  
    2.times {//循環兩次  
        def borrow = pool.borrow()//從對象池中借一個對象  
        println borrow.hashCode()//打印對象的hashcode  
        pool.back(borrow)//將對象歸還對象池  
    }  
    output(pool.size())//打印對象池中的對象數量  
  
}  
  
/**  
 * 一個簡單的類  
 */  
static class Demo {  
  
}

控制檯打印:

1528769018
878991463
878991463
22:06:05:561 main 1
22:06:05 uptime:1 s

可以看出第一次借出和後兩次借出的對象非同一對象,而後兩次借出的是同一個對象。基本實現了一個對象池該有的功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章