Use JakartaCommonsPool Object pool technology

Source: Internet
Author: User
1. Why does it take a lot of time to create and initialize new objects using the object pool technology. In the initialization of such objects, if you rely on rpc Remote calls to create objects, such as connecting to remote service resources through socket or http, the most typical is the database service and RemoteQueue ), establish a connection

1. Why does it take a lot of time to create and initialize new objects using the object pool technology. In the initialization of such objects, if you rely on rpc Remote calls to create objects, such as connecting to remote service resources through socket or http, the most typical is the database service and Remote Queue (Remote Queue), establish a connection-send data-

1. Why is object pool technology used?

It may take a lot of time to create and initialize a new object. In the initialization of such objects, if you rely on rpc Remote calls to create objects, such as connecting to remote service resources through socket or http, the most typical is the database service and Remote Queue. The process of establishing a connection-> sending data-> receiving connection-> releasing a connection is undoubtedly very heavy for the customer service end. When a large number or frequent generation of such objects is required, the performance may be affected. To solve this problem, the Object Pooling technology can be used at the software level, while the Jakarta Commons Pool framework is a powerful foreign aid for processing Object Pooling.

2. technical explanation of Object pool

The basic idea of the Object pool is to save the used objects and use them again when this object is needed for the next time, this reduces the overhead caused by frequent object creation to some extent. The Object used as the "Container" for saving objects. It is called the "Object Pool" (or "Pool" for short ).

Not all objects are suitable for pooling-because maintaining the object pool also causes certain overhead. Pooling objects with low overhead during generation may lead to a situation where the overhead of maintaining the object pool is greater than that of generating new objects, reducing performance. However, for objects with considerable overhead during generation, Pooling technology is an effective strategy to improve performance.

3. Jakarta Commons Pool Object Pool framework

In this framework, there are two main types of objects:

PoolableObjectFactory: used to manage the generation, activation, suspension, checksum, and destruction of pooled objects;

ObjectPool: used to manage the lending and return of objects to be pooled, and notify PoolableObjectFactory to complete relevant work;

Correspondingly, the process of using the Pool framework is divided into two actions: "Creating PoolableObjectFactory" and "using ObjectPool.

3.1 Use PoolableObjectFactory

The Pool framework uses PoolableObjectFactory to manage pooled objects. When an ObjectPool instance needs to process the generation, activation, suspension, checksum, and destruction of pooled objects, it will call the corresponding method of the PoolableObjectFactory instance associated with it for operation.

PoolableObjectFactory is an interface defined in the org. apache. commons. pool package. In actual use, you need to use a specific implementation of this interface. The Pool framework itself does not contain any kind of PoolableObjectFactory implementation, which needs to be created as needed.

The general steps for creating PoolableObjectFactory are as follows:

Create a class that implements the PoolableObjectFactory interface.

Import org. apache. commons. pool. PoolableObjectFactory;

Public class PoolableObjectFactorySample

Implements PoolableObjectFactory {

Private static int counter = 0;

}

Add an Object makeObject () method for this class. This method is used to generate new objects when necessary.

Public Object makeObject () throws Exception {

Object obj = String. valueOf (counter ++ );

System. err. println ("Making Object" + obj );

Return obj;

}

Add a void activateObject (Object obj) method for this class. This method is used to "Activate" the object and set it to a suitable state for getting started.

Public void activateObject (Object obj) throws Exception {

System. err. println ("Activating Object" + obj );

}

Add a void passivateObject (Object obj) method for this class. This method is used to "Suspend" the object and set it to a suitable state for starting sleep.

Public void passivateObject (Object obj) throws Exception {

System. err. println ("Passivating Object" + obj );

}

Add a boolean validateObject (Object obj) method to this class. This method is used to verify whether a specific object is still valid. expired objects are automatically handed over to the destroyObject Method for destruction.

Public boolean validateObject (Object obj ){

Boolean result = (Math. random ()> 0.5 );

System. err. println ("Validating Object"

+ Obj + ":" + result );

Return result;

}

Add a void destroyObject (Object obj) method for this class. This method is used to destroy objects that have been invalidated by validateObject.

Public void destroyObject (Object obj) throws Exception {

System. err. println ("Destroying Object" + obj );

}

The last completed PoolableObjectFactory looks like this:

Import org. apache. commons. pool. poolableObjectFactory; public class PoolableObjectFactorySample implements PoolableObjectFactory {private static int counter = 0; public Object makeObject () throws Exception {Object obj = String. valueOf (counter ++); System. err. println ("Making Object" + obj); return obj;} public void activateObject (Object obj) throws Exception {System. err. println ("Activating Object" + obj);} public void passivateObject (Object obj) throws Exception {System. err. println ("Passivating Object" + obj);} public boolean validateObject (Object obj) {/* determines the Object as invalid at a 1/2 probability */boolean result = (Math. random ()> 0.5); System. err. println ("Validating Object" + obj + ":" + result); return result;} public void destroyObject (Object obj) throws Exception {System. err. println ("Destroying Object" + obj );}}

3.2 use ObjectPool

With the appropriate PoolableObjectFactory, you can start to invite the ObjectPool for the same performance.

ObjectPool is an interface defined in the org. apache. commons. pool package. You need to use this interface to implement it. The Pool framework itself contains several ready-made ObjectPool implementations that can be directly used. If none of them are not suitable, you can also create them as needed. For details about the creation method, refer to the documentation and source code of the Pool framework.

ObjectPool usage is similar to this:

Generate an instance of the PoolableObjectFactory class to be used.

PoolableObjectFactory factory = new PoolableObjectFactorySample ();

Use this PoolableObjectFactory instance as the parameter to generate an instance that implements the ObjectPool interface (for example, StackObjectPool) and act as the object pool.

ObjectPool pool = new StackObjectPool (factory );

To retrieve an Object from the Object pool, call the Object borrowObject () method of the Object pool.

Object obj = null;

Obj = pool. borrowObject ();

When you need to put the Object back into the Object pool, call the void returnObject (Object obj) method of the Object pool.

Pool. returnObject (obj );

When an object pool is no longer needed, call the void close () method of the Object pool to release the resources it occupies.

Pool. close ();

These operations may throw an exception and need to be processed separately.

For the complete process of using ObjectPool, refer to this Code:

Import org. apache. commons. pool. objectPool; import org. apache. commons. pool. poolableObjectFactory; import org. apache. commons. pool. impl. stackObjectPool; public class ObjectPoolSample {public static void main (String [] args) {Object obj = null; PoolableObjectFactory factory = new PoolableObjectFactorySample (); ObjectPool pool = new StackObjectPool (factory ); try {for (long I = 0; I <100; I ++) {System. o Ut. println ("=" + I + "="); obj = pool. borrowObject (); System. out. println (obj); pool. returnObject (obj);} obj = null; // It is explicitly set to null as the identifier of the returned object} catch (Exception e) {e. printStackTrace ();} finally {try {if (obj! = Null) {// avoid returning an object to the pool twice. returnObject (obj);} pool. close ();} catch (Exception e) {e. printStackTrace ();}}}}

In summary, the UML diagram is as follows:

3.3 thread security issues

Sometimes the Pool framework may be used in a multi-threaded environment. At this time, problems related to the thread security of the Pool framework will occur.

Because ObjectPool and KeyedObjectPool are both in org. apache. commons. the interface defined in the pool, but the interface cannot use "synchronized" to modify the method. Therefore, whether each method in the ObjectPool is a synchronous method depends on the specific implementation. In addition, simply using the synchronization method does not allow the object to rest in a multi-threaded environment.

As for the implementation of several built-in objectpools in the Pool framework, they all take into account the usage in a multi-threaded environment to a certain extent. However, it cannot be said that they are completely "thread-safe.

For example, this code sometimes has some strange performances, and the final output result is larger than expected:

Import org. apache. commons. pool. objectPool; import org. apache. commons. pool. impl. stackObjectPool; class UnsafePicker extends Thread {private ObjectPool pool; public UnsafePicker (ObjectPool op) {pool = op;} public void run () {Object obj = null; try {/* seems to be ...... */If (pool. getNumActive () <5) {sleep (long) (Math. random () * 10); obj = pool. borrowObject () ;}} catch (Exception e) {e. printStackTrace () ;}} public class UnsafeMultiThreadPoolingSample {public static void main (String [] args) {ObjectPool pool = new StackObjectPool (new BasePoolableObjectFactorySample ()); thread ts [] = new Thread [20]; for (int j = 0; j <ts. length; j ++) {ts [j] = new Unsa FePicker (pool); ts [j]. start () ;}try {Thread. sleep (1000);/* However ...... */System. out. println ("NumActive:" + pool. getNumActive ();} catch (Exception e) {e. printStackTrace ();}}}

To avoid this situation, we need to take further measures:

Import org. apache. commons. pool. objectPool; import org. apache. commons. pool. impl. stackObjectPool; class SafePicker extends Thread {private ObjectPool pool; public SafePicker (ObjectPool op) {pool = op;} public void run () {Object obj = null; try {/* slightly add processing */synchronized (pool) {if (pool. getNumActive () <5) {sleep (long) (Math. random () * 10); obj = pool. borrowObject () ;}} catch (Exception e) {e. printStackTrace () ;}} public class SafeMultiThreadPoolingSample {public static void main (String [] args) {ObjectPool pool = new StackObjectPool (new BasePoolableObjectFactorySample ()); thread ts [] = new Thread [20]; for (int j = 0; j <ts. length; j ++) {ts [j] = new SafePicker (pool); ts [j]. start () ;}try {Thread. sleep (1, 1000); System. out. println ("NumActive:" + pool. getNumActive ();} catch (Exception e) {e. printStackTrace ();}}}

Basically, the Pool framework is thread-compatible. However, special processing is required to be used in a multi-threaded environment.

4. Example of thread pool in Jedis

Let's take a look at an example. As we are studying Redis recently, we need to find a reliable redis driver. There are many open source projects. For details, see the link. Jedis is one of the earliest ones. Compared with other drivers, Jedis provides a JedisPool for managing redis connections. Its main tasks include Pool. java, JedisPool. java, and JedisPoolConfig. java.

Pool. java encapsulates a GenericObjectPool, which is responsible for the generation, verification, and destruction of Jedis connections.

package redis.clients.util;?import org.apache.commons.pool.PoolableObjectFactory;import org.apache.commons.pool.impl.GenericObjectPool;import redis.clients.jedis.exceptions.JedisConnectionException;import redis.clients.jedis.exceptions.JedisException;?public abstract class Pool {    private final GenericObjectPool internalPool;?    public Pool(final GenericObjectPool.Config poolConfig,            PoolableObjectFactory factory) {        this.internalPool = new GenericObjectPool(factory, poolConfig);    }?    @SuppressWarnings("unchecked")    public T getResource() {        try {            return (T) internalPool.borrowObject();        } catch (Exception e) {            throw new JedisConnectionException(                    "Could not get a resource from the pool", e);        }    }?    public void returnResourceObject(final Object resource) {        try {            internalPool.returnObject(resource);        } catch (Exception e) {            throw new JedisException(                    "Could not return the resource to the pool", e);        }    }?    public void returnBrokenResource(final T resource) {    returnBrokenResourceObject(resource);    }?    public void returnResource(final T resource) {    returnResourceObject(resource);    }?    protected void returnBrokenResourceObject(final Object resource) {        try {            internalPool.invalidateObject(resource);        } catch (Exception e) {            throw new JedisException(                    "Could not return the resource to the pool", e);        }    }?    public void destroy() {        try {            internalPool.close();        } catch (Exception e) {            throw new JedisException("Could not destroy the pool", e);        }    }}

JedisPool. java inherits Pool. java and writes an Inner Class-BasePoolableObjectFactory internally, which is used to input the basic methods for establishing, destroying, and verifying connections in the thread Pool when creating a JedisPool instance.

package redis.clients.jedis;?import org.apache.commons.pool.BasePoolableObjectFactory;import org.apache.commons.pool.impl.GenericObjectPool.Config;?import redis.clients.util.Pool;?public class JedisPool extends Pool {?    public JedisPool(final Config poolConfig, final String host) {        this(poolConfig, host, Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);    }?    public JedisPool(String host, int port) {        this(new Config(), host, port, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);    }?    public JedisPool(final String host) {        this(host, Protocol.DEFAULT_PORT);    }?    public JedisPool(final Config poolConfig, final String host, int port,            int timeout, final String password) {        this(poolConfig, host, port, timeout, password, Protocol.DEFAULT_DATABASE);    }?    public JedisPool(final Config poolConfig, final String host, final int port) {        this(poolConfig, host, port, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);    }?    public JedisPool(final Config poolConfig, final String host, final int port, final int timeout) {        this(poolConfig, host, port, timeout, null, Protocol.DEFAULT_DATABASE);    }?    public JedisPool(final Config poolConfig, final String host, int port, int timeout, final String password,                     final int database) {        super(poolConfig, new JedisFactory(host, port, timeout, password, database));    }??    public void returnBrokenResource(final BinaryJedis resource) {    returnBrokenResourceObject(resource);    }?    public void returnResource(final BinaryJedis resource) {    returnResourceObject(resource);    }?    /**     * PoolableObjectFactory custom impl.     */    private static class JedisFactory extends BasePoolableObjectFactory {        private final String host;        private final int port;        private final int timeout;        private final String password;        private final int database;?        public JedisFactory(final String host, final int port,                final int timeout, final String password, final int database) {            super();            this.host = host;            this.port = port;            this.timeout = timeout;            this.password = password;            this.database = database;        }?        public Object makeObject() throws Exception {            final Jedis jedis = new Jedis(this.host, this.port, this.timeout);?            jedis.connect();            if (null != this.password) {                jedis.auth(this.password);            }            if( database != 0 ) {                jedis.select(database);            }?            return jedis;        }?        public void destroyObject(final Object obj) throws Exception {            if (obj instanceof Jedis) {                final Jedis jedis = (Jedis) obj;                if (jedis.isConnected()) {                    try {                        try {                            jedis.quit();                        } catch (Exception e) {                        }                        jedis.disconnect();                    } catch (Exception e) {?                    }                }            }        }?        public boolean validateObject(final Object obj) {            if (obj instanceof Jedis) {                final Jedis jedis = (Jedis) obj;                try {                    return jedis.isConnected() && jedis.ping().equals("PONG");                } catch (final Exception e) {                    return false;                }            } else {                return false;            }        }    }}

JedisPoolConfig inherits GenericObjectPool. Config, which is used to specify some thread pool initialization parameters.

package redis.clients.jedis;?import org.apache.commons.pool.impl.GenericObjectPool.Config;?/** * Subclass of org.apache.commons.pool.impl.GenericObjectPool.Config that * includes getters/setters so it can be more easily configured by Spring and * other IoC frameworks. *  * Spring example: *  *    *  *    *    *  * For information on parameters refer to: *  * http://commons.apache.org/pool/apidocs/org/apache/commons/pool/impl/ * GenericObjectPool.html */public class JedisPoolConfig extends Config {    public JedisPoolConfig() {        // defaults to make your life with connection pool easier :)        setTestWhileIdle(true);        setMinEvictableIdleTimeMillis(60000);        setTimeBetweenEvictionRunsMillis(30000);        setNumTestsPerEvictionRun(-1);    }?    public int getMaxIdle() {        return maxIdle;    }?    public void setMaxIdle(int maxIdle) {        this.maxIdle = maxIdle;    }?    public int getMinIdle() {        return minIdle;    }?    public void setMinIdle(int minIdle) {        this.minIdle = minIdle;    }?    public int getMaxActive() {        return maxActive;    }?    public void setMaxActive(int maxActive) {        this.maxActive = maxActive;    }?    public long getMaxWait() {        return maxWait;    }?    public void setMaxWait(long maxWait) {        this.maxWait = maxWait;    }?    public byte getWhenExhaustedAction() {        return whenExhaustedAction;    }?    public void setWhenExhaustedAction(byte whenExhaustedAction) {        this.whenExhaustedAction = whenExhaustedAction;    }?    public boolean isTestOnBorrow() {        return testOnBorrow;    }?    public void setTestOnBorrow(boolean testOnBorrow) {        this.testOnBorrow = testOnBorrow;    }?    public boolean isTestOnReturn() {        return testOnReturn;    }?    public void setTestOnReturn(boolean testOnReturn) {        this.testOnReturn = testOnReturn;    }?    public boolean isTestWhileIdle() {        return testWhileIdle;    }?    public void setTestWhileIdle(boolean testWhileIdle) {        this.testWhileIdle = testWhileIdle;    }?    public long getTimeBetweenEvictionRunsMillis() {        return timeBetweenEvictionRunsMillis;    }?    public void setTimeBetweenEvictionRunsMillis(            long timeBetweenEvictionRunsMillis) {        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;    }?    public int getNumTestsPerEvictionRun() {        return numTestsPerEvictionRun;    }?    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {        this.numTestsPerEvictionRun = numTestsPerEvictionRun;    }?    public long getMinEvictableIdleTimeMillis() {        return minEvictableIdleTimeMillis;    }?    public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;    }?    public long getSoftMinEvictableIdleTimeMillis() {        return softMinEvictableIdleTimeMillis;    }?    public void setSoftMinEvictableIdleTimeMillis(            long softMinEvictableIdleTimeMillis) {        this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;    }?}

1. Why does it take a lot of time to create and initialize new objects using the object pool technology. In the initialization of such objects, if you rely on rpc Remote calls to create objects, such as connecting to remote service resources through socket or http, the most typical is the database service and Remote Queue (Remote Queue), establish a connection-> send data-> receive connection [......]

Continue reading

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.