Apache common 프로젝트 중 Pool이라는 것이 있습니다.
Object Pool을 개발 할 수 있는데요..
간단한 예제를 만들어보려고 합니다.
Pool은 풀링 메카니즘을 쉽게 구현 할 수 있도록 해주는 프로젝트입니다.
DBCP도 이것을 활용해서 구현되어있구요..
기본적으로 Pooling 해서 사용 할 클래스를 하나 만들어 보겠습니다.
MyPoolableObject
그리고 필요한 것이
위 클래스의 객체를 생성하여주는 Factory 클래스입니다.
MyPoolableObjectFactory
위와 같이 두개의 클래스와 Pool에서 제공되는 GenericObjectPool을 사용하면 간단히 테스트 코드를
만들어 볼 수 있습니다.
TestPool
결과는 아래와 같이 나옵니다.
이렇게만 봐서는 제대로 Pooling이 되는지 알기 어렵습니다.
테스트 코드를 조금만 변경하여 보겠습니다.
TestPool
결과가 아래와 같이 나옵니다.
결과를 보니 제대로 Pooling이 안되는 것 같네요..
Pooling이 되었다면 static으로 선언한 MyPoolableObject의 count가 전부 1이 되어야 할 것 입니다.
단 한번 객체로 만들어 진 이후에는 계속 Pooling이 되어 사용되었을테니까요.. 하지만 위 결과에서는
count가 지속적으로 증가하고 있고 이 이야기는 바로 매번 객체가 새로 생성되었다는 뜻 입니다.
뭐가 문제일까요?
for문을 보면 GenericObjectPool마저 매번 새로 생성하고 있는 것이 보입니다.
Pool자체가 매번 새롭게 생성되기 때문에 Pooling의 대상이 되는 MyPoolableObject도 매번 새롭게 생성되는 것 입니다.
Pool에 넣어두었지만 Pool자체가 새로 만들어지기 때문이죠..
그래서 아래처럼 코드를 수정해보겠습니다.
TestPool
Pool은 단 한번만 생성하고 for문으로 돌면서 객체를 Pooling합니다.
결과가 잘 나올 것 같습니다만 실제로 돌려보면 결과는 아래와 같이 나옵니다.
count는 여전히 매번 증가하고 있으며
더군다나 i가 7에서 프로그램이 그대로 lock에 걸려버립니다.
이건 또 무슨일일까요???
코드를 보면 객체를 가져가는 부분은 있지만 (borrowObject)
사용하고 반납하는 부분이 없습니다.
GenericObjectPool에서의 Pooling max 값이 기본으로 8로 되어 있기 때문에
요청이 올 때마다 MyPoolableObject를 생성하였는데, 8개까지만 생성하고 더 이상
넘겨 줄 것이 없기 때문에 (반환을 하지 않았으므로...)
그대로 멈추고 있는 상황인 것 입니다.
실제 프로그램에서는 위 같은 상황이 되면 어딘가에서 객체를 반환 해 줄 때까지
프로그램이 멈춰있게 될 것 입니다.
그래서 코드를 아래와 같이 다시 한번 수정하여 보겠습니다.
TestPool
returnObject를 추가하였고
결과는 아래와 같습니다.
아~!!
이제 좀 제대로 되는 것 같네요.
실제로 사용하려면
여러가지 최적화된 설정도 필요하고
GenericObjectPool도 최소한 JVM안에서는 싱글턴으로 구현 되어야 할 것 입니다.
Object Pool을 개발 할 수 있는데요..
간단한 예제를 만들어보려고 합니다.
Pool은 풀링 메카니즘을 쉽게 구현 할 수 있도록 해주는 프로젝트입니다.
DBCP도 이것을 활용해서 구현되어있구요..
기본적으로 Pooling 해서 사용 할 클래스를 하나 만들어 보겠습니다.
MyPoolableObject
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package skt.tmall.process.share.search.searchable.pool; | |
/** | |
* @author need4spd, need4spd@cplanet.co.kr, 2011. 5. 20. | |
* | |
*/ | |
public class MyPoolableObject { | |
private static int count = 0; | |
public MyPoolableObject() { | |
count++; | |
} | |
public int getCount() { | |
return count; | |
} | |
} |
그리고 필요한 것이
위 클래스의 객체를 생성하여주는 Factory 클래스입니다.
MyPoolableObjectFactory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.pool.BasePoolableObjectFactory; | |
/** | |
* @author need4spd, need4spd@cplanet.co.kr, 2011. 5. 20. | |
* | |
*/ | |
public class MyPoolableObjectFactory extends BasePoolableObjectFactory { | |
@Override | |
public Object makeObject() throws Exception { | |
return new MyPoolableObject(); | |
} | |
} |
위와 같이 두개의 클래스와 Pool에서 제공되는 GenericObjectPool을 사용하면 간단히 테스트 코드를
만들어 볼 수 있습니다.
TestPool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.pool.impl.GenericObjectPool; | |
/** | |
* @author need4spd, need4spd@cplanet.co.kr, 2011. 5. 20. | |
* | |
*/ | |
public class TestPool { | |
public static void main(String[] args) throws Exception { | |
GenericObjectPool genericObjectPool = new GenericObjectPool(new MyPoolableObjectFactory()); | |
MyPoolableObject obj = (MyPoolableObject)genericObjectPool.borrowObject(); | |
System.out.println(obj+ "count : " + obj.getCount()); | |
} | |
} |
결과는 아래와 같이 나옵니다.
MyPoolableObject@ab95e6count : 1
이렇게만 봐서는 제대로 Pooling이 되는지 알기 어렵습니다.
테스트 코드를 조금만 변경하여 보겠습니다.
TestPool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.pool.impl.GenericObjectPool; | |
/** | |
* @author need4spd, need4spd@cplanet.co.kr, 2011. 5. 20. | |
* | |
*/ | |
public class TestPool { | |
public static void main(String[] args) throws Exception { | |
for(int i = 0; i < 10; i++) { | |
GenericObjectPool genericObjectPool = new GenericObjectPool(new MyPoolableObjectFactory()); | |
MyPoolableObject obj = (MyPoolableObject)genericObjectPool.borrowObject(); | |
System.out.println("i : " + i); | |
System.out.println(obj+ "count : " + obj.getCount()); | |
} | |
} | |
} |
결과가 아래와 같이 나옵니다.
i : 0
MyPoolableObjectcount : 1
i : 1
MyPoolableObjectcount : 2
i : 2
MyPoolableObjectcount : 3
i : 3
MyPoolableObjectcount : 4
i : 4
MyPoolableObjectcount : 5
i : 5
MyPoolableObjectcount : 6
i : 6
MyPoolableObjectcount : 7
i : 7
MyPoolableObjectcount : 8
i : 8
MyPoolableObjectcount : 9
i : 9
MyPoolableObjectcount : 10
Pooling이 되었다면 static으로 선언한 MyPoolableObject의 count가 전부 1이 되어야 할 것 입니다.
단 한번 객체로 만들어 진 이후에는 계속 Pooling이 되어 사용되었을테니까요.. 하지만 위 결과에서는
count가 지속적으로 증가하고 있고 이 이야기는 바로 매번 객체가 새로 생성되었다는 뜻 입니다.
뭐가 문제일까요?
for문을 보면 GenericObjectPool마저 매번 새로 생성하고 있는 것이 보입니다.
Pool자체가 매번 새롭게 생성되기 때문에 Pooling의 대상이 되는 MyPoolableObject도 매번 새롭게 생성되는 것 입니다.
Pool에 넣어두었지만 Pool자체가 새로 만들어지기 때문이죠..
그래서 아래처럼 코드를 수정해보겠습니다.
TestPool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.pool.impl.GenericObjectPool; | |
/** | |
* @author need4spd, need4spd@cplanet.co.kr, 2011. 5. 20. | |
* | |
*/ | |
public class TestPool { | |
public static void main(String[] args) throws Exception { | |
GenericObjectPool genericObjectPool = new GenericObjectPool(new MyPoolableObjectFactory()); | |
for(int i = 0; i < 10; i++) { | |
MyPoolableObject obj = (MyPoolableObject)genericObjectPool.borrowObject(); | |
System.out.println("i : " + i); | |
System.out.println(obj.getClass().getSimpleName()+ "count : " + obj.getCount()); | |
} | |
} | |
} |
Pool은 단 한번만 생성하고 for문으로 돌면서 객체를 Pooling합니다.
결과가 잘 나올 것 같습니다만 실제로 돌려보면 결과는 아래와 같이 나옵니다.
i : 0
MyPoolableObjectcount : 1
i : 1
MyPoolableObjectcount : 2
i : 2
MyPoolableObjectcount : 3
i : 3
MyPoolableObjectcount : 4
i : 4
MyPoolableObjectcount : 5
i : 5
MyPoolableObjectcount : 6
i : 6
MyPoolableObjectcount : 7
i : 7
MyPoolableObjectcount : 8
더군다나 i가 7에서 프로그램이 그대로 lock에 걸려버립니다.
이건 또 무슨일일까요???
코드를 보면 객체를 가져가는 부분은 있지만 (borrowObject)
사용하고 반납하는 부분이 없습니다.
GenericObjectPool에서의 Pooling max 값이 기본으로 8로 되어 있기 때문에
요청이 올 때마다 MyPoolableObject를 생성하였는데, 8개까지만 생성하고 더 이상
넘겨 줄 것이 없기 때문에 (반환을 하지 않았으므로...)
그대로 멈추고 있는 상황인 것 입니다.
실제 프로그램에서는 위 같은 상황이 되면 어딘가에서 객체를 반환 해 줄 때까지
프로그램이 멈춰있게 될 것 입니다.
그래서 코드를 아래와 같이 다시 한번 수정하여 보겠습니다.
TestPool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.pool.impl.GenericObjectPool; | |
/** | |
* @author need4spd, need4spd@cplanet.co.kr, 2011. 5. 20. | |
* | |
*/ | |
public class TestPool { | |
public static void main(String[] args) throws Exception { | |
GenericObjectPool genericObjectPool = new GenericObjectPool(new MyPoolableObjectFactory()); | |
for(int i = 0; i < 10; i++) { | |
MyPoolableObject obj = (MyPoolableObject)genericObjectPool.borrowObject(); | |
System.out.println("i : " + i); | |
System.out.println(obj.getClass().getSimpleName()+ "count : " + obj.getCount()); | |
genericObjectPool.returnObject(obj); | |
} | |
} | |
} |
returnObject를 추가하였고
결과는 아래와 같습니다.
i : 0
MyPoolableObjectcount : 1
i : 1
MyPoolableObjectcount : 1
i : 2
MyPoolableObjectcount : 1
i : 3
MyPoolableObjectcount : 1
i : 4
MyPoolableObjectcount : 1
i : 5
MyPoolableObjectcount : 1
i : 6
MyPoolableObjectcount : 1
i : 7
MyPoolableObjectcount : 1
i : 8
MyPoolableObjectcount : 1
i : 9
MyPoolableObjectcount : 1
이제 좀 제대로 되는 것 같네요.
실제로 사용하려면
여러가지 최적화된 설정도 필요하고
GenericObjectPool도 최소한 JVM안에서는 싱글턴으로 구현 되어야 할 것 입니다.