美文网首页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对象池实战

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