This is intended as a (mostly) GC-free alternative to
java.util.concurrent.ConcurrentLinkedQueuewhen the requirement is to create an unbounded queue with no requirement to shrink the queue. The aim is to provide the bare minimum of required functionality as quickly as possible with minimum garbage.
ConcurrentLinkedQueue 을 사용할 경우 Node 를 사용하기 때문에 poll() 하게 되면 해당 Node 는 GC의 대상이 된다. 수많은 요청을 처리해야 하는 Tomcat의 특성 상 GC가 자주 일어나는 것은 치명적이다. (GC가 일어나면 STW(Stop-the-World) 가 일어나 GC thread를 제외한 모든 스레드가 멈추기 때문이다)synchronized 을 사용해서 동기화를 구현한 것을 확인할 수 있다.public class SynchronizedQueue<T> {
public static final int DEFAULT_SIZE = 128;
private Object[] queue;
private int size; // Queue의 크기
private int insert = 0; // 새로 삽입할 인덱스
private int remove = 0; // 가장 오래된 인덱스
public SynchronizedQueue() {
this(DEFAULT_SIZE);
}
public SynchronizedQueue(int initialSize) {
queue = new Object[initialSize];
size = initialSize;
}
...
public synchronized boolean offer(T t) {
queue[insert++] = t;
if (insert == size) {
insert = 0; // 원형 큐임을 짐작할 수 있음.
}
if (insert == remove) {
expand(); // 2배로 늘림
}
return true;
}
insert == remove 는 큐가 꽉 찼다는 것을 의미하므로 expand() 메서드를 통해 Queue 의 크기를 2배 확장한다.public synchronized T poll() {
if (insert == remove) {
// empty
return null;
}
@SuppressWarnings("unchecked")
T result = (T) queue[remove];
queue[remove] = null;
remove++;
// Wrap
if (remove == size) {
remove = 0;
}
return result;
}
insert == remove 은 위에서와는 의미가 살짝 다른데, 배열이 비어있다는 것을 의미한다.public synchronized int size() {
int result = insert - remove;
if (result < 0) {
result += size;
}
return result;
}
public synchronized void clear() {
queue = new Object[size];
insert = 0;
remove = 0;
}
synchronized 로 동기화가 되어있다.