공공부하자개발 · 영어 학습 노트
자바
실무 확장Excel · 파일 업로드 · DB 연동0/22 완료
  • 01Excel(XLSX) 구조와 순수 JDK로 읽기/쓰기
  • 02Apache POI로 Excel 업로드/다운로드
  • 03파일 업로드/다운로드 서버 (HttpServer)
  • 04JDBC 기초와 트랜잭션 (H2)
  • 05MyBatis 어노테이션 매퍼로 쿼리 연동
  • 06MyBatis XML 매퍼 · Oracle 방언 · PageHelper · Spring Boot
  • 07REST API 서버와 JSON
  • 08Vue 3 SPA 와 Java 서버 연동
  • 09@Scheduled 운영
  • 10로깅 실무: 레벨·계층, MDC 추적, 예외·성능, 마스킹, 롤링, JSON 로그
  • 11외부 API 연동
  • 12테스트 실무
  • 13암호화·개인정보 보호
  • 14인코딩·한글 실무
  • 15@Transactional 심화
  • 16긴 작업 비동기 처리와 진행률
  • 17SFTP·FTP 파일 연계
  • 18로컬 캐시와 @Cacheable
  • 19메일·알림 발송
  • 20웹 보안 체크리스트
  • 21빌드 도구와 폐쇄망 의존성 반입
  • 22성능 측정: p50·p95·p99, 측정 계층, JFR, JMH 함정, 자체 부하 테스트, 병목 순위
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 실무 확장 › 18 / 22

로컬 캐시와 @Cacheable

TTL, 크기 제한, 스탬피드 방지, 무효화, Caffeine 설정
섹션 7진행 0 / 22
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6연습 문제7정리‹ 이전다음 ›

3. 코드 예제

실행 방법입니다. 외부 jar 는 필요 없습니다.

powershell
cd java-src\extension\18_cache
C:\project\jdk-21.0.8\bin\javac -encoding UTF-8 *.java
C:\project\jdk-21.0.8\bin\java -Dstdout.encoding=UTF-8 Main   # 약 1초

Cache<K,V> — TTL·스탬피드 방지·LRU 근사

java
// Cache.get: computeIfAbsent 로 같은 키의 동시 미스를 1회로 합친다
Entry<V>[] created = new Entry[1];
Entry<V> entry = store.compute(key, (k, old) -> {
    if (old != null && old.expireAtMillis > now) {
        return old; // 그 사이 다른 스레드가 이미 채웠음
    }
    V value = loader.apply(k);
    created[0] = new Entry<>(value, now + ttl.toMillis(), now);
    return created[0];
});

store 는 ConcurrentHashMap 이고, compute 는 같은 키에 대해 원자적으로 실행되므로 여러 스레드가 동시에 미스해도 loader.apply(k) 는 한 번만 불립니다. Clock 을 주입받기 때문에, 테스트에서는 MutableClock 으로 시간을 앞당겨 TTL 만료를 즉시 재현할 수 있습니다.

데모 실행 결과

text
== 1. 느린 조회 캐싱 ==
첫 호출 291ms, 둘째 호출 1ms (캐시 적중)     ← 첫 호출만 200ms sleep 을 탄다
hit=1 miss=1 size=1 hitRatio=50.0%

== 2. TTL 만료 ==
loader 호출 횟수: 2 (기대값 2)              ← 적중 1회는 재호출 없음
hit=1 miss=2 size=1 hitRatio=33.3%

== 3. 캐시 스탬피드 방지 ==
동시 미스 10개, loader 실행 1회 (기대값 1)   ← 10 스레드가 동시에 미스해도 1회

== 4. 쓰기 후 invalidate ==
수정 전: old-name
수정 후: new-name                          ← invalidate 뒤 새 값으로 재계산

== 5. 크기 제한 초과 시 제거 ==
최대 크기 3인데 5개 입력 -> 현재 크기: 3     ← 오래된 항목부터 제거
hit=0 miss=5 size=3 hitRatio=0.0%

예제 2 의 TTL 만료는 실제로 5분을 기다리지 않고, MutableClock.advance(Duration.ofMinutes(6)) 로 시계를 앞당겨 즉시 재현했습니다. 예제 3 은 CountDownLatch 로 10개 스레드를 동시에 출발시켜 진짜 동시 접근 상황을 만들었습니다.

예제 직접 실행

아래 폴더를 JDK 21 로 컴파일하고 실행합니다. 외부 jar 를 쓰는 레슨은 java-src/lib 를 클래스패스에 넣습니다.

cd java-src\extension\18_cache
javac -encoding UTF-8 *.java && java Main

:: 외부 jar 가 필요한 레슨
javac -encoding UTF-8 -cp "..\..\lib\*;." *.java && java -cp "..\..\lib\*;." Main
코드 예제
  • Cache<K,V> — TTL·스탬피드 방지·LRU 근사
  • 데모 실행 결과
이전 섹션2 핵심 원리3 / 7다음 섹션4 응용 변형 예제