JDK 5까지 쓰레드 동기화 큐로 임무를 수행하던 LinkedBlockingQueue의 경우 동기화 대기가 상당한 부하를 주었습니다.
6.x에서 SynchronousQueue를 사용하면 단순히 take와 put을 하는 경우 몇 배나 높은 성능을 기대할 수 있습니다. 이 구조가 다중 쓰레드 내에서 안전하면서 왜 빨라지는가는 이 포스트의 성격과 무관하므로 생략합니다만, 다음의 링크를 참조하면 도움이 됩니다.
http://suein1209.tistory.com/325
Pool에서 가져오기
쨌든 Pool을 구현하면 기본적으로 다중 쓰레드에 노출될 가능성을 염두 해야 하므로 가디언 패턴을 따라야 하지만, SynchronousQueue를 사용하면 간단히 정리할 수 있습니다.
우선 큐를 만들고 객체를 얻기 위한 GET함수를 작성해 보죠.
static SynchronousQueue<Sample> _pool = new SynchronousQueue<Sample>(); static String GET( final String $key ){ Sample result = null; if( _pool.size() > 0 ){ try{ result = _pool.take().init( $key ); }catch( InterruptedException $e ){} }else{ result = new Sample().init( $key ); } return result; }
내용은 간단합니다. _pool에 뭔가 있으면 take로 가져오고 아니면 새로 만들게 됩니다.
만약 _pool.size() > 0 조건을 생략하면 GET함수를 호출한 쓰레드가 대기하게 되니 주의해야 합니다.
Pool에 반환하기
Sample 클래스를 간단히 살펴보죠.
class Sample{ private String _key; public void init( String $key ){ _key = $key; } public void run(){ Log( _key ); try{ _pool.put( this ); }catch( InterruptedException $e ){} } }
여기서 핵심은 run에 있는 _pool.put 입니다. 실행을 완수하고 나면 다시 _pool로 돌아가는 것이죠.
결론
이러한 간단한 로직만으로 구현된 가변 Pool은 다음과 같은 상황에서 쓸모가 많습니다.
- 여러 번 사용되지만 동시에 몇 개까지 사용될지 예측할 수 없다.
- app의 생명주기 전반에 걸쳐 꾸준히 사용된다.
- 즉시 지워야 할 정도로 큰 객체가 아니다.
- 사용된 객체는 Pool로 돌아갈 타이밍이 정해져 있다.
위의 경우 가변 Pool을 사용하면 다음과 같은 장점이 생깁니다.
- new를 최소화 한다.
- 필요할 때 생성하므로 new를 지연한다.
- 사용 후 재사용하게 되므로 GC에 부담을 줄인다.
recent comment