美文网首页Java
GenericObjectPool对象池实战

GenericObjectPool对象池实战

作者: shiy4n | 来源:发表于2019-07-06 23:53 被阅读5次

通常一个对象创建/销毁的时候非常耗时,我们不会频繁的创建销毁它,而是考虑复用。复用对象的一种做法就是对象池,将创建好的对象放入池中维护起来,下次再用的时候直接拿池中已经创建好的对象继续用

GenericObjectPool

GenericObjectPool是一个通用对象池框架,我们可以借助它实现一个健壮的对象池

维护一个对象池需要实现以下基本的功能:

  • 创建对象

  • 借出对象

  • 验证对象

  • 归还对象

  • 销毁对象

GenericObjectPool 需要通过构造器注入一个PooledObjectFactory对象,而PooledObjectFactory中提供了维护对象池的方法

public interface PooledObjectFactory<T> {
    PooledObject<T> makeObject() throws Exception;

    void destroyObject(PooledObject<T> var1) throws Exception;

    boolean validateObject(PooledObject<T> var1);

    void activateObject(PooledObject<T> var1) throws Exception;

    void passivateObject(PooledObject<T> var1) throws Exception;
}

以Socket连接池为例


    public class ConnectionFactory extends BasePooledObjectFactory<Socket> {
        // 创建socket对象
        public Socket create() throws Exception {
            String[] ipAndPort = host.split(":");
            if (ipAndPort.length < 2) {
                throw new ParseHostException();
            }
            Integer port = Integer.parseInt(ipAndPort[1]);
            Socket socket = new Socket(ipAndPort[0], port);
            socket.setSoTimeout(timeOut);
            return socket;
        }
        // 包装为可维护的对象
        public PooledObject<Socket> wrap(Socket socket) {
            return new DefaultPooledObject<Socket>(socket);
        }

        /**
         * 能关的都给他关了
         * @param pooledObject
         * @throws Exception
         */
        public void destroyObject(PooledObject<Socket> pooledObject) throws Exception {
            Socket socket = pooledObject.getObject();
            if (socket != null) {
                socket.getInputStream().close();
                socket.getOutputStream().close();
                socket.close();
            }
        }

        // 验证对象,Pool对象可以设置借出归还时候是否需要验证对象
        public boolean validateObject(PooledObject<Socket> pooledObject) {
            Socket socket = pooledObject.getObject();
            return socket != null && !socket.isClosed() && socket.isConnected();
        }

        /**
         * 钝化归还对象,说白了就是对归还的对象清理
         * 清空输入流,避免因为上一个请求字节未读取完导致inputStream非空,对下一个产生影响
         * @param p
         * @throws Exception
         */
        @Override
        public void passivateObject(PooledObject<Socket> p) throws Exception {
            Socket socket = p.getObject();
            InputStream inputStream = socket.getInputStream();
            int available = inputStream.available();
            if (available > 0) {
                inputStream.skip(available);
            }
        }
    }

有了上面的ConnectionFactory,就可以创建对象池了

public class ConnectionPoolExecutor implements Executor {

    private GenericObjectPool<Socket> connectionPool = new GenericObjectPool<>(new ConnectionFactory());

    private String host;
    private int timeOut = 5000;
    // 池的大小
    private int poolSize = 5;
    // 最少空闲对象个数
    private int miniIdle = 0;
    // 最大空闲对象个数
    private int maxIdle = poolSize;
    // 驱除策略,对象池内部维护了一个定时线程,如果配置了此属性,会定时调用此类来校验对象是否可用
    private String evictionPolicyClassName;
    // 驱除对象的定时线程执行间隔
    private int timeBetweenEvictionRunsMillis=5000;
    // 驱除对象的定时线程每次校验对象个数
    private int numTestsPerEvictionRun = 1;


    public ConnectionPoolExecutor() {
        this.connectionPool.setTestOnBorrow(true);
        this.connectionPool.setTestOnReturn(true);
        this.connectionPool.setTestWhileIdle(true);
    }

    public void execute(Command command) throws ExecutionException {
          try {
              Socket socket = this.connectionPool.borrowObject();
              InputStream inputStream = socket.getInputStream();
              command.request(inputStream);
              command.response(socket.getOutputStream());

              this.connectionPool.returnObject(socket);
          } catch (Exception e) {
              throw new ExecutionException(e);
          } finally {

          }
      }

      public void dispose() {
          this.connectionPool.close();
      }
    //....以下省略

上面的代码可以看到一个Executor接口,这是为了增强代码扩展性,抽象出来的接口

public interface Executor {

    void execute(Command command) throws ExecutionException;

    void dispose();
}

public interface Command {

    void request(InputStream inputStream);

    void response(OutputStream outputStream);
}

我们最终的目的是为了对外提供阻塞长连接服务,但socket对象池并非唯一实现方式。参考Command模式,我们只需要实现不同的executor就可以扩展不同的socket创建方式


/**
 * 提供阻塞式socket服务
 */
public interface ServiceProvider {

    void sendSimpleCommand();

}


public class ServiceProviderImpl implements ServiceProvider {

    private Executor executor;

    private void setExecutor(Executor executor) {
        this.executor = executor;
    }

    public void sendSimpleCommand() {
        try {
            executor.execute(new Command() {
                public void request(InputStream inputStream) {

                }

                public void response(OutputStream outputStream) {

                }
            });
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

相关文章

  • GenericObjectPool对象池实战

    通常一个对象创建/销毁的时候非常耗时,我们不会频繁的创建销毁它,而是考虑复用。复用对象的一种做法就是对象池,将创建...

  • GenericObjectPool对象池使用优化

    背景 某应用1.0性能测试 服务强依赖于mysql, 许多接口都会请求mysql 对mysql的请求用Generi...

  • Unity 类对象池资源池对象池

    类对象池 包含创建对象池,取对象池中的内容,回收。 对象管理类 因为使用加载AB包的时候可能会频繁创建类,但是ne...

  • Laya_2D示例项目使用对象池预制体的创建、位置设置和添加到父

    //使用对象池创建盒子 1.对象池的使用 对象池创建箱子 let box = Laya.Pool.getI...

  • Unity--简单的对象池

    简单的对象池分三步走: 建立对象池 拿到对象 回收对象 Test为对象池,Obj为自动回收的物体 Test.cs ...

  • 对象池

    一、对象池概述: 对于那些实例化开销比较大,并且生命周期比较短的对象,我们可以通过池就行管理。所谓池,就相当于一个...

  • 对象池

  • 对象池

    概要 看到现在,Netty之设计精妙,令人感叹。优化至极,令人发指。在高并发场景下,对象的分配的损耗是很大的,特别...

  • 对象池

    讲在前面 为什么要有对象池?我们需要一种类型的实例时候往往回去new一个这样会造成gc问题对象池根本奥义就在于一个...

  • 对象池

    UGUI 中使用的对象池 在 C:\Files\Unity\Projects\UGUITest\PackageSo...

网友评论

    本文标题:GenericObjectPool对象池实战

    本文链接:https://www.haomeiwen.com/subject/fmlvhctx.html