2010-04-14 3 views
1

모든 요청 (공유 Ehcache)시 사용자 저장소에서 캐시를 검색하는 대신 사용자 정보를 캐시하는 서블릿이 있습니다. 내가 가진 문제는 클라이언트가 멀티 스레드이며, 경우에 그들이가 인증되기 전에, 나는 내 로그에이를 얻을, 두 개 이상의 동시 요청을 할 것입니다 :전체 캐시를 잠그지 않고 캐시 키 잠그기

Retrieving User [Bob] 
Retrieving User [Bob] 
Retrieving User [Bob] 
Returned [Bob] ...caching 
Returned [Bob] ...caching 
Returned [Bob] ...caching 

내가 원하는 것 것이 있다는 것입니다 첫 번째 요청이 다른 두 개의 요청이 차단다면, 사용자 서비스를 호출 할 - 때 첫 번째 요청을 반환하고 객체를 캐시, 다른 두 요청은 통과 : 나는에 잠금에 대해 생각했습니다

Retrieving User [Bob] 
blocking... 
blocking... 
Returned [Bob] ...caching 
[Bob] found in cache 
[Bob] found in cache 

문자열 "Bob"(왜냐하면 인턴으로 인해 항상 같은 대상 이니까?). 그게 효과가 있니? 캐시가 실제로 존재하는 키를 추적하고 그 주위에 잠금 메커니즘을 구축하면 유효한 객체가 검색되면 반환됩니다. 감사.

답변

4

잠금을 독점적으로 제어 할 수 없다면 교착 상태가 발생하지 않을 것이라고 보장 할 수 없습니다. Interned String은 전 세계적으로 볼 수 있으므로 열악한 후보입니다.

대신 키와 해당 잠금 사이의 맵을 사용하십시오. 동시지도에 동기화 된 액세스를 사용하거나 ConcurrentMap을 사용할 수 있습니다. 나는 어느 것이 더 싼지 잘 모르겠다. 그러나 나는 당신의 의도를 간결하게 표현했기 때문에 ConcurrentMap을 향한다. 그것으로, 당신은 동시에 여러 스레드에 의해 캐시 된 값의 읽을 수 있도록 같은 멋진 무언가를 할 수있는, 아직 값을 업데이트 할 필요가있을 때 또 다른 스레드가 단독 잠금을 얻을 수있다;

ReadWriteLock trial = new ReentrantReadWriteLock(fair); 
ReadWriteLock lock = locks.putIfAbsent(key, trial); 
if (lock == null) { 
    /* The current thread won the race to create lock for key. */ 
    lock = trial; 
} 

(A ReadWriteLock는 선택 사항입니다 사용 .)

잠금이 이미 존재하기 때문에 폐기되는 많은 잠금을 만드는 데 많은 비용이 부과 될 수 있습니다. 또는 java.util.concurrent없이 이전 런타임을 사용할 수도 있습니다. 그와 같은 경우에는지도에 동기화 할 수 있습니다 :

Object lock; 
synchronized (locks) { 
    if (locks.containsKey(key)) 
    lock = locks.get(key); 
    else { 
    lock = new Object(); 
    locks.put(key, object); 
    } 
} 
+0

이것은 내가 생각하고있는 것에 매우 가깝습니다. 인턴 된 문자열을 잠그는 것은 어떤 이유로 든 정말 나쁜 생각처럼 보였습니다. 그러나이 시나리오에서 Map의 모든 호출을 잠그고 있습니다. 그러나 이것은 모든 스레드가 공유하는 다른 캐시 (성능 현명한)와 다른 캐시가 아닌 것 같습니다. 나는이 오버 헤드가 여전히 빠른 속도로 내 불필요한 호출을 내 사용자 인증 공급자에게 보내는 것이라고 생각합니다. – Gandalf

0

지도로 캐싱하는 경우 키를 잠그면 제안한 것이됩니다.

관련 문제