程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 池化,卷積和池化

池化,卷積和池化

編輯:JAVA綜合教程

池化,卷積和池化


  對於那些創建耗時較長,或者資源占用較多的對象,比如網絡連接,線程之類的資源,通常使用池化來管理這些對象,從而達到提高性能的目的。比如數據庫連接池(c3p0, dbcp), java的線程池 ExecutorService.Apache Commons Pool提供一套池化規范接口,以及實現通用邏輯,我們只需要要實現其抽象出來的方法就可以。Commons Pool主要有以下幾個對象   PooledObject:這個就是前面所說需要池化的資源,被池化的對象可以抽離出共有屬性,如,創建時間,狀態,最近一次使用時間等   PooledObjectFactory: 對象工廠,負責對PooledOjbect的創建,狀態驗證,銷毀之類的工作   ObjectPool: 對象池,它是負責和對象使用者直接打交道的, 對使用者提供獲取對象,返還對象接口   英文不太好的同學可能被這幾個對象的命名搞暈,其實世間萬物的道理都是想通的。如果把圖書館的書比作PooledObject 的話,那麼圖書館就是ObjectPool,圖書館為了管理書,對書添加了入庫時間,書借存狀態等用於管理的屬性。圖書館(ObjectPool)對借書人提供借書,還書的服務(即接口)。而書(PooledObject )的印刷,質量檢驗,回收(有點不現實)等實實在在的工作還是得交給印刷廠(PooledObjectFactory )來做。其流程關系如下:   下面看看如何使用Commons Pool如何實現自己的對象池。創建自己的對象池大致需要以下工作,   1. 首先你已經編寫好了你的資源對象(這部分不屬於池化內容),之後編寫實現apache的PooledObjectFactory<T>接口的Factory類,這是編寫自己對象池最主要的工作。你的Factory可能需要添加一些用於池化對象的初始化 ,池化對象的驗證等參數作為成員變量。   2. 編寫自己的Pool類,讓其繼承或者內部引用apache的GenericObjectPool<T>,GenericObjectPool實現了ObjectPool接口,已經封裝了對池化對象的生命周期管理邏輯   3. 可選部分,繼承apache的GenericObjectPoolConfig,重寫構造器,添加一些適合自己業務場景的初始化參數。   我們以Jedis的源碼為例,學習它的實現。我們先看下使用JedisPool操作Redis的簡單例子
package com.eg.test.redis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class TestPool {
     public static void main(String[] args) {
        //JedisPoolConfig繼承apache的GenericObjectPoolConfig,配置Pool的相關參數如下:
        JedisPoolConfig config = new JedisPoolConfig(); 
        //如果賦值為-1,則表示不限制;如果pool已經分配了maxActive個jedis實例,則此時pool的狀態為exhausted(耗盡)。 
        config.setMaxTotal(500); 
        //控制一個pool最多有多少個狀態為idle(空閒的)的jedis實例。 
        config.setMaxIdle(5); 
        //表示當borrow(引入)一個jedis實例時,最大的等待時間,如果超過等待時間,則直接拋出JedisConnectionException; 
        config.setMaxWaitMillis(30000);; 
        //在borrow一個jedis實例時,是否提前進行validate操作;如果為true,則得到的jedis實例均是可用的; 
        config.setTestOnBorrow(true); 
       
        JedisPool pool = new JedisPool(config, "192.168.2.191", 8888); 
        //從pool中獲取對象
        Jedis jedis = pool.getResource(); 
        String value = jedis.get("someKey");
       
     }
}

  首先看JedisFactory的實現:

class JedisFactory implements PooledObjectFactory<Jedis> {
     private final AtomicReference<HostAndPort> hostAndPort = new AtomicReference<HostAndPort>();
     private final int connectionTimeout;
     private final int soTimeout;

     //省略構造函數,都是一些初始化成員變量的操作

     @Override
     public void activateObject(PooledObject<Jedis> pooledJedis) throws Exception {
           final BinaryJedis jedis = pooledJedis.getObject();
           if (jedis.getDB() != database) {
                jedis.select(database);
           }
     }

     @Override
     public void destroyObject(PooledObject<Jedis> pooledJedis) throws Exception {
           final BinaryJedis jedis = pooledJedis.getObject();
           if (jedis.isConnected()) {
                try {
                     try {
                           jedis.quit();
                     } catch (Exception e) {
                     }
                     jedis.disconnect();
                } catch (Exception e) {
                }
           }
     }

     @Override
     public PooledObject<Jedis> makeObject() throws Exception {
           final HostAndPort hostAndPort = this.hostAndPort.get();
           final Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort(), connectionTimeout, soTimeout, ssl,
                   sslSocketFactory, sslParameters, hostnameVerifier);
           try {
                jedis.connect();
                if (null != this.password) {
                     jedis.auth(this.password);
                }
                if (database != 0) {
                     jedis.select(database);
                }
                if (clientName != null) {
                     jedis.clientSetname(clientName);
                }
           } catch (JedisException je) {
                jedis.close();
                throw je;
           }
           return new DefaultPooledObject<Jedis>(jedis);
     }
     @Override
     public void passivateObject(PooledObject<Jedis> pooledJedis) throws Exception {
           // TODO maybe should select db 0? Not sure right now.
     }
     @Override
     public boolean validateObject(PooledObject<Jedis> pooledJedis) {
           final BinaryJedis jedis = pooledJedis.getObject();
           try {
                HostAndPort hostAndPort = this.hostAndPort.get();
                String connectionHost = jedis.getClient().getHost();
                int connectionPort = jedis.getClient().getPort();
                return hostAndPort.getHost().equals(connectionHost) && hostAndPort.getPort() == connectionPort
                        && jedis.isConnected() && jedis.ping().equals("PONG");
           } catch (final Exception e) {
                return false;
           }
     }
}

  我們看到JedisFactory代碼較少,但是邏輯很清晰。該Factory將作為ObjectPool的成員變量,其中四個重寫的方法被ObjectPool管理對象生命周期的時候調用。makeobject()方法負責創建Jedis實例,成功調用connect()方法建立有狀態的socket連接之後,返回一個包裝了jedis的DefaultPooledObject對象,DefaultPooledObject實現了關於統計池化對象狀態信息的PooledObject接口。validateObject()方法用於對對象狀態的檢驗,Jedis對象的狀態通過socket的ping-pong來驗證連接是否正常。destroyObject()方法用來銷毀對象,Jedis對象將會斷開連接,回收資源。

  再看JedisPool的實現,由於JedisPool繼承Pool<T>,所以我們主要看Pool<T>的部分代碼:

public abstract class Pool<T> implements Closeable {
     protected GenericObjectPool<T> internalPool;

     public Pool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) {
           initPool(poolConfig, factory);
     }

     public boolean isClosed() {
           return this.internalPool.isClosed();
     }
     public void initPool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) {
           if (this.internalPool != null) {
                try {
                     closeInternalPool();
                } catch (Exception e) {
                }
           }
           this.internalPool = new GenericObjectPool<T>(factory, poolConfig);
     }
     public T getResource() {
           try {
                return internalPool.borrowObject();
           } catch (NoSuchElementException nse) {
                throw new JedisException("Could not get a resource from the pool", nse);
           } catch (Exception e) {
                throw new JedisConnectionException("Could not get a resource from the pool", e);
           }
     }
     protected void returnResourceObject(final T resource) {
           if (resource == null) {
                return;
           }
           try {
                internalPool.returnObject(resource);
           } catch (Exception e) {
                throw new JedisException("Could not return the resource to the pool", e);
           }
     }

     public void addObjects(int count) {
           try {
                for (int i = 0; i < count; i++) {
                     this.internalPool.addObject();
                }
           } catch (Exception e) {
                throw new JedisException("Error trying to add idle objects", e);
           }
     }
}
  JedisPool通過內部引用GenericObjectPool,包裝其接口的裝飾者模式,相比繼承來說這種模式更加靈活。JedisPool的構造方法需要將JedisFactory以及JedisPoolConfig創建標准的ObjectPool作為自己的成員變量。所以pool.getResource()方法的背後還是調用PoolObject.borrowObject()。     最後我們稍微看下JedisPoolConfig,只是做了一些預初始化參數的工作。
public class JedisPoolConfig extends GenericObjectPoolConfig {
     public JedisPoolConfig() {
           // defaults to make your life with connection pool easier :)
           setTestWhileIdle(true);
           setMinEvictableIdleTimeMillis(60000);
           setTimeBetweenEvictionRunsMillis(30000);
           setNumTestsPerEvictionRun(-1);
     }
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved