본문 바로가기

Java

[JAVA] GenericObjectPool에 대해 알아보고 사용해보자

Object Pooling

  • 오브젝트의 Pool을 만들어두고 해당 웅덩이 안에서 필요할 때마다 객체를 꺼내서 사용하는 것
  • 잦은 오브젝트 할당으로 인한 오버헤드가 감소된다.

GenericObjectPool

Apache Commons Pool 라이브러리의 일부로서 객체 풀링(object pooling)을 구현하기 위한 클래스 중 하나입니다.

  • 객체 풀은 자주 생성 및 소멸되는 객체를 관리하고 재사용함으로써 성능을 최적화하는데 사용합니다.
  • 일반적으로는 데이터베이스 연결, 소켓 연결, 스레드 등과 같이 생성 및 제거 비용이 높은 리소스를 효율적으로 사용하는 데 도움이 됩니다.

특징

  1. 커스터마이징 가능한 구성 : 객체 풀을 구성할 수 있는 다양한 설정을 제공 합니다
    • 최소 및 최대 객체 수, 리소스 생성 및 제거, 오브젝트 유효성 검사
  2. 객체 리사이클링 : 객체가 사용한 후에 풀로 반환되며, 다른 클라이언트가 재사용할 수 있도록 풀에서 관리됩니다.
  3. 객체 유효성 검사 : 풀에서 가져오는 객체가 유효한지 확인하기 위한 사용자 정의 검증로직을 지원합니다. 유효성 검사에 실패하는 경우 해당 객체는 폐기됩니다.
  4. Blocking 및 Non-blocking 동작 : 클라이언트가 객체를 요청했을 때, 객체가 사용 가능하지 않은 경우 Blocking 및 Non-blocking 동작을 지원합니다.
  5. 객체 고정화 클래스 : PooledObject 인터페이스를 구현하여 객체의 생명주기를 추적하고 관리합니다.

이와 같이 GenericObjectpol은 객체 풀을 구현하고 사용자 정의 리소스를 관리하는데 매우 유용합니다. 이를 통해 메모리와 리소스 사용을 최적화하고, 속도와 성능을 향상 시킬 수 있습니다.

Java에서 사용해보기

gradle

implementation 'commons-pool:commons-pool:1.6'

Clone.java

@Getter
@Setter
public class Clone {
	private long id;
	private String name;
	private static int count;

	public Clone() {
		count++;
	}
}

ClonePool.java

@Component
public class ClonePool extends BasePoolableObjectFactory<Clone> {

	@Override
	public Clone makeObject() throws Exception {
		return new Clone();
	}
}

테스트 코드

1) 반환 X

@Slf4j
@SpringBootTest
public class PoolTest {

	@Test
	public void poolTest() throws Exception {
		GenericObjectPool genericObjectPool = new GenericObjectPool(new ClonePool());
		log.info("===============start==============");

		for (int i = 0; i < 10; i++) {
			Clone clone = (Clone)genericObjectPool.borrowObject();
			log.info(clone + ", " + Clone.getCount());
		}

		log.info("===============close==============");
	}
}

borrowObject를 통해서 객체를 풀링하고 다시 반환을 하지 않았기 때문에 객체 풀의 객체 디폴트 제한 값인 8에서 객체를 더 풀링해오지 못하고 멈춘 것을 확인할 수 있다.

com.dnd.jpatest.PoolTest                 : ===============start==============
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@43e9a8a2, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@178617da, 2
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 3
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@74ed1d35, 4
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@7acf07b2, 5
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@5d50e7f6, 6
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@54fbaa65, 7
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@48e3017a, 8

2) 반환 O

@Slf4j
@SpringBootTest
public class PoolTest {

	@Test
	public void poolTest() throws Exception {
		GenericObjectPool genericObjectPool = new GenericObjectPool(new ClonePool());
		log.info("===============start==============");

		for (int i = 0; i < 1000; i++) {
			Clone clone = (Clone)genericObjectPool.borrowObject();
			log.info(clone + ", " + Clone.getCount());
			genericObjectPool.returnObject(clone);
		}

		log.info("===============close==============");
	}
}
com.dnd.jpatest.PoolTest                 : ===============start==============
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest                 : ===============close==============

borrowObject 후 returnObject를 통해 객체를 반환하기 때문에 count도 계속 1이고 같은 객체를 가져오는 것을 확인할 수 있다.

3) 객체 삭제

@Slf4j
@SpringBootTest
public class PoolTest {

	@Test
	public void poolTest() throws Exception {
		GenericObjectPool genericObjectPool = new GenericObjectPool(new ClonePool());
		log.info("===============start==============");

		for (int i = 0; i < 10; i++) {
			Clone clone = (Clone)genericObjectPool.borrowObject();
			log.info(clone + ", " + Clone.getCount());
			genericObjectPool.invalidateObject(clone);
		}

		log.info("===============close==============");
	}
}

returnObject → inavalidObject로 변경하였습니다.

com.dnd.jpatest.PoolTest                 : ===============start==============
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@54fbaa65, 1
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@48e3017a, 2
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@4a937d43, 3
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@10264cb0, 4
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@19877453, 5
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@49bf5ec8, 6
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@18174bd9, 7
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@3af6d7a7, 8
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@18711946, 9
com.dnd.jpatest.PoolTest                 : com.dnd.jpatest.Clone@2b8b5d9e, 10
com.dnd.jpatest.PoolTest                 : ===============close==============

반환된 객체가 아닌 새로운 객체가 생성되기 때문에 객체의 주소가 다르고, count 값이 증가됩니다.

Config

@Configuration
public class ObjectPoolConfig {

	@Bean
	public GenericObjectPool objectnPool() {
		GenericObjectPool pool = new GenericObjectPool(new ClonePool());

		pool.setMaxActive(10); // 최대 객체 풀 수
		pool.setMaxIdle(5);   // 최대 비활성 객체 수
		pool.setMinIdle(2);   // 최소 비활성 객체 수

		return pool;
	}
}

Config 파일을 통해 객체 풀에 대한 초기 설정을 할 수 있다.

'Java' 카테고리의 다른 글

Java Executors, ExecutorService  (0) 2024.05.31
OpenSearch를 사용하면서 발생한 문제  (0) 2023.11.02
[JAVA] Socket 연결 시 Timeout 설정  (0) 2023.10.20
[Java] try-with-resource (AutoCloseable)  (0) 2023.09.25
[Java] - Synchronized  (0) 2023.09.22