In previous post under Apache Pool I showed you how to create a pool of objects.
The pool of objects are not classified based on specific criteria. So as a result if you are expecting that Apache Pool should return an object based on specific criteria is not possible.
To solve this requirement Apache Pool provides KeyedPooledObjectFactory interface, through which you can classify pool of objects based on specific criteria.
In this post I will explain how to use KeyedPooledObjectFactory with an example.
Lets say you want to create a pool of thread objects grouped under NORMAL and ADVANCED categories.
First we will create a class which provides our own implementation of KeyedPooledObjectFactory interface as shown below
ThreadKeyedPoolObjectFactory
1 package package3;
2
3 import org.apache.commons.pool2.KeyedPooledObjectFactory;
4 import org.apache.commons.pool2.PooledObject;
5 import org.apache.commons.pool2.impl.DefaultPooledObject;
6
7 public class ThreadKeyedPoolObjectFactory implements KeyedPooledObjectFactory<String, Thread> {
8 private int normalThreadObjectCount = 0;
9 private int advancedThreadObjectCount = 0;
10 public static enum keys {NORMAL, ADVANCED};
11
12 @Override
13 public void activateObject(String key, PooledObject<Thread> p) throws Exception {
14 }
15
16 @Override
17 public void destroyObject(String key, PooledObject<Thread> p) throws Exception {
18 }
19
20 @Override
21 public PooledObject<Thread> makeObject(String key) throws Exception {
22 keys enumKey = keys.valueOf(key);
23 String threadName = (keys.NORMAL.equals(enumKey)) ? keys.NORMAL.name() : keys.ADVANCED.name();
24 int currentTheadObjectCount = 0;
25
26 if(keys.NORMAL.equals(enumKey)) {
27 normalThreadObjectCount = normalThreadObjectCount + 1;
28 currentTheadObjectCount = normalThreadObjectCount;
29 } else {
30 advancedThreadObjectCount = advancedThreadObjectCount + 1;
31 currentTheadObjectCount = advancedThreadObjectCount;
32 }
33
34 threadName = threadName + currentTheadObjectCount;
35 Thread thread = new Thread(threadName);
36 DefaultPooledObject<Thread> defaultPooledObject = new DefaultPooledObject<Thread>(thread);
37 return defaultPooledObject;
38 }
39
40 @Override
41 public void passivateObject(String key, PooledObject<Thread> p) throws Exception {
42 }
43
44 @Override
45 public boolean validateObject(String key, PooledObject<Thread> p) {
46 return true;
47 }
48 }
In the above code, we provide implementations for “makeObject” and “validateObject” methods.
The “makeObject” method takes a “key” (string datatype) as an argument and based on the value of “key” (which will be either NORMAL or ADVANCED) will create Thread objects.
The Thread objects created are wrapped with an instance of DefaultPooledObject. This instance is returned from “makeObject” method.
Next I will show you the main code.
Main Class
1 package package3;
2
3 import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
4
5 public class ThreadPoolExample3 {
6 public static void main(String[] args) {
7 GenericKeyedObjectPool<String, Thread> genericKeyedObjectPool = new GenericKeyedObjectPool<String, Thread>(new ThreadKeyedPoolObjectFactory());
8 genericKeyedObjectPool.setMaxTotal(20);
9 genericKeyedObjectPool.setMaxTotalPerKey(10);
10
11 Thread normalThread1 = null, normalThread2 = null;
12 Thread advancedThread = null;
13 try {
14 normalThread1 = genericKeyedObjectPool.borrowObject(ThreadKeyedPoolObjectFactory.keys.NORMAL.name());
15 System.out.println(normalThread1);
16 advancedThread = genericKeyedObjectPool.borrowObject(ThreadKeyedPoolObjectFactory.keys.ADVANCED.name());
17 System.out.println(advancedThread);
18 normalThread2 = genericKeyedObjectPool.borrowObject(ThreadKeyedPoolObjectFactory.keys.NORMAL.name());
19 System.out.println(normalThread2);
20 } catch(Exception exception) {
21 exception.printStackTrace();
22 } finally {
23 if(normalThread1 != null) {
24 genericKeyedObjectPool.returnObject(ThreadKeyedPoolObjectFactory.keys.NORMAL.name(), normalThread1);
25 }
26
27 if(normalThread2 != null) {
28 genericKeyedObjectPool.returnObject(ThreadKeyedPoolObjectFactory.keys.NORMAL.name(), normalThread2);
29 }
30
31 if(advancedThread != null) {
32 genericKeyedObjectPool.returnObject(ThreadKeyedPoolObjectFactory.keys.ADVANCED.name(), advancedThread);
33 }
34 genericKeyedObjectPool.close();
35 }
36 }
37 }
In the above code, at line 7, we create an instance of GenericKeyedObjectPool and pass an instance of ThreadKeyedPoolObjectFactory as constructor argument.
GenericKeyedObjectPool through “borrowObject” method, takes key name and calls “ThreadKeyedPoolObjectFactory” to create an Thread instance.
GenericKeyedObjectPool internally maintains a Map where map key is value of key variable passed to “borrowObject” method and value is the instance returned by “ThreadKeyedPoolObjectFactory”.
In the above code, we are creating three instances of Thread two under NORMAL group and one from ADVANCED group.
In finally clause, we are returning those objects to object pool by calling “returnObject” method on “GenericKeyedObjectPool” instance.
In this way we can create an object pool where objects are classified under particular criteria.