自从研究了 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

可以看出第一次借出和后两次借出的对象非同一对象,而后两次借出的是同一个对象。基本实现了一个对象池该有的功能。