Skip to content

Commit

Permalink
refactor: ConcurrentLinkedQueue와 WeakReference 사용하여 activeCounters 최적화
Browse files Browse the repository at this point in the history
- Thread가 GC에 의해 수집될 수 있도록 참조를 완전히 제거
- 빠른 삽입 작업을 위해 List를 ConcurrentLinkedQueue로 변경
- 사용되지 않는 Counter 객체가 GC에 의해 수거될 수 있도록 WeakReference 적용
- 동시성 환경에서 activeCounters 접근 및 수정 시 스레드 안전성 보장
  • Loading branch information
miiiinju1 committed Aug 15, 2024
1 parent a5f1670 commit d454429
Showing 1 changed file with 14 additions and 13 deletions.
27 changes: 14 additions & 13 deletions logbat/src/main/java/info/logbat/dev/util/ThreadLocalLongAdder.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
package info.logbat.dev.util;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.lang.ref.WeakReference;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public class ThreadLocalLongAdder {

private final ThreadLocal<Counter> localCounter = new ThreadLocal<>();
private final Queue<WeakReference<Counter>> activeCounters = new ConcurrentLinkedQueue<>();

/**
* ConcurrentHashMap을 사용해야하는 이유
* <p>
* 두 Thread가 같은 hashCode를 가지고 동시에 새 Counter를 추가하려 할 때, 한 Thread의 Counter가 다른 Thread의 Counter로 덮어쓰일
* 가능성이 있습니다.
*/
private final Map<Thread, Counter> activeCounters = new ConcurrentHashMap<>(200);
private long value = 0L;

public void increment() {
Counter counter = localCounter.get();

// Thread 내의 Counter가 없으면, 새로운 Counter를 생성하여 ThreadLocal과 activeCounters에 추가
// WeakReference를 사용하여 GC가 Counter를 수거할 수 있도록 함
if (counter == null) {
counter = new Counter();
localCounter.set(counter);
activeCounters.put(Thread.currentThread(), counter);
activeCounters.add(new WeakReference<>(counter));
}

// Thread 내의 Counter에 증가연산을 수행하여, 경쟁상태가 발생하지 않음
Expand All @@ -43,10 +39,15 @@ public void reset() {

private void flush() {
synchronized (activeCounters) {
for (Counter counter : activeCounters.values()) {
value += counter.getValue();
activeCounters.removeIf(weakCounter -> {
Counter counter = weakCounter.get();
if (counter == null) {
return true; // Thread가 제거되어 WeakReference가 null을 가리키면 해당 엔트리 제거
}
value += (counter.getValue());
counter.resetValue();
}
return false;
});
}
}

Expand Down

0 comments on commit d454429

Please sign in to comment.