본문 바로가기

프로그래밍/Design Pattern

Object Pool Pattern (오브젝트 풀 패턴) 의 이해



Object Pool Pattern 패턴?

 - 객체를 필요로 할때 풀에 요청을 하고, 반환하고 일련의 작업을 수행하는 패턴.

   많은 수의 인스턴스를 생성할때 혹은 무거운 오브젝트를 매번 인스턴스화 할때 성능 향상을 가져오기도 합니다.

   예를들어, 데이터베이스에 접속하는 여러 객체를 만들때 매번 새로 생성하는 것보단,

   미리 생성된 풀에서 객체를 반환받아오는 것이 더 이득 입니다.

   이런 문제로 JDBC 에서는 JDBC Connection Pool 을 제공하고 있으며 Thread Pool 역시 오브젝트 풀이 기본 원리 입니다.

 

이번 포스팅의 목적은 실제 오브젝트풀이 무엇인지, 어떤방식으로 작동하는지 원리에 대해 알아 보고자 합니다.

 

실제 아래 코드는 사용하는데 제한이 있습니다. (실제 오브젝트 풀은 고려해야할 사항이 어느정도 존재합니다)

따라서, 이번 포스팅의 목적만을 위해 간단한 풀을 코드로 구현하면서 확인해보겠습니다.

 

 

※ 참고!!

 아파치제단의 오픈소스 프로젝트인 Apache Common 프로젝트 Pool Framework 에  다양한 오브젝트 풀 관련

 기능을 제공하고 있습니다.

 

 

 

 

 

 

 

 

<그림 1> Simple Object Pool Class Diagram

 

 

구글 및 여러 사이트에 오브젝트 풀에 대해 검색을 하면 다양한 방식의 오브젝트 풀 구현방법을 얻으실수 있습니다.

 

오브젝트 풀은 객체를 관리하는 그룹과 같다고 보시면 됩니다.

일반적 코드에서 객체를 생성하고 관리하는것이 아니라 Pool 이라는 곳에

객체를 생성하고 반환하는 행위등이 이루어진다고 보시면 됩니다.

 

만약 몬스터 객체를 무조건 10개만 내에만 생성해야 하고, 미리 생성해둔 곳에서 가져와서 쓰고 싶다.

라는 조건이 생긴다면 오브젝트 풀 패턴을 이용하시면 좀 더 효율적인 관리를 할 수 있습니다.

 

우선 소스코드를 살펴보시겠습니다.

(제네릭 타입을 받는 오브젝트 풀 클래스 이므로 제네릭에 대한 이해가 필요합니다.)

 

 - ObjectPool Class

 

public class ObjectPool<T>  {	
	
	private List<T> poolList = new ArrayList<>();
	private Class<T> classObj;
	private int maxPoolSize = 10;	

	
	public ObjectPool(Class<T> classObj) {
		this.classObj = classObj;
	}
	
	public ObjectPool(Class<T> classObj, int maxPoolSize) {
		this.classObj = classObj;
		this.maxPoolSize = maxPoolSize;
	}
		
	
	//객체 생성
	public T borrowObject() throws InstantiationException, IllegalAccessException {
		
		//풀사이즈 초과
		if (poolList.size() > maxPoolSize) {
			throw new PoolSizeOutException("PoolSizeOutException");
		}
		
		T newInstance = classObj.newInstance();
		poolList.add(newInstance);
		return newInstance;		
	}
		
	
	//객체 반환
	public boolean returnObject(T obj) {
		return poolList.remove(obj);
	}
	
	
	//객체 유효성 검사 (풀에 있는 객체인지)
	public boolean invalidateObject(T obj) {
		for(T data : poolList) {
			if (data != null && data.equals(obj)) {
				return true;
			}	
		}
		return false;		
	}
	
	
	public T getObject() {
		
		if (poolList.size() < 1) {
			return null;
		}

		//Top Pop
		T instance = poolList.get(poolList.size() - 1);		
		returnObject(instance);
		
		return instance;
	}	
		
	
	static class PoolSizeOutException extends RuntimeException {

		public PoolSizeOutException(String message) {
			super(message);
		}
		
	}
	
}

 

 

 

ObjectPool 클래스 설명

 [1] 생성자 : 클래스의 정보를 받고, maxPoolSize 만큼 풀의 크기를 제한.

 [2] borrowObject : 객체를 생성하고 풀 리스트에 객체를 추가.

 [3] returnObject : 풀에 있는 객체를 반환 (제거)

 [4] invalidateObject : 풀에 객체가 존재하는지 유효성 검사

 [5] getObject : 후입선출 (LIFO) 즉 스택의 POP 처럼 마지막에 들어온 객체가 먼저 반환.

 

PoolSizeOutException 이너 클래스 는 간단히 풀사이즈가 초과에 대한 사용자 정의 Exception

 

 

public static void main(String[] args) { ObjectPool<StringBuffer> pool = new ObjectPool<StringBuffer>(StringBuffer.class, 10); try { StringBuffer object1 = pool.borrowObject(); StringBuffer object2 = new StringBuffer(); System.out.println(pool.invalidateObject(object1)); System.out.println(pool.invalidateObject(object2)); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } }


 

결과

 

오브젝트 풀 클래스를 가지고 이제 실제 사용해 보겠습니다.

객체를 10개를 제한하는 풀을 만들었고, StringBuffer 를 담도록 하고,

borrowObject 를 통해 객체를 생성하여 반환, 그리고 StringBuffer 를 직접 인스턴스화

이렇게 두가지를 하고 유효성 검사를 하면 결과가 어떻게 나올까요?

 

결과 :

당연히 true, false 순으로 나옵니다.
object1 객체는 풀에서 생성하고 반환 받았고, object2 는 직접 인스턴스화 해서 생성하였기 때문에 풀에 존재하지 않습니다.

자 어려움없이 오브젝트 풀 클래스를 간단히 제작해 보고 이해를 해보았습니다.

 

오브젝트 풀 패턴은 다양한 구현 방법이 존재하기도 합니다.

따라서, 스레드 환경에서는 동기화 처리에 대한 고려도 필요하고,

ObjectPool 을 더 유연하게 구현하는 다양한 방법이 존재하므로,

깊은 공부와 이해는 아래 사이트를 참고하시면 되겠습니다.

 

 

※ 본 포스팅의 소스코드등 직접 제작하였으므로, 퍼갈때 반드시 출처를 남겨주세요. 

 

 

유용한 관련 참고 사이트

[1] Wiki

     http://en.wikipedia.org/wiki/Object_pool_pattern

[2] Refactoring and Design Patterns

     http://patterns.instantinterfaces.nl/current/Refactoring-and-Design-Patterns-PAT-OBJP.html