2017-01-01 1 views
2

저는 Cassandra와 Datastax Java 드라이버를 사용하고 있습니다. 준비된 문장을 캐싱하여 다시 사용하려고합니다. 내 위의 getStatement 방법은 여러 스레드에 의해 호출됩니다putIfAbsent와 함께 "get/check/put"을 사용하십시오.

private static final Map<String, PreparedStatement> holder = new ConcurrentHashMap<>(); 

    public BoundStatement getStatement(String cql) { 
    Session session = TestUtils.getInstance().getSession(); 
    PreparedStatement ps = holder.get(cql); 
    // no statement is cached, create one and cache it now. 
    if (ps == null) { 
     synchronized (this) { 
     ps = holder.get(cql); 
     if (ps == null) { 
      ps = session.prepare(cql); 
      holder.put(cql, ps); 
     } 
     } 
    } 
    return ps.bind(); 
    } 

그래서 그것이 스레드 안전 확인해야합니다. Java 7에서 작동하므로 불행히도 computeIfAbsent을 사용할 수 없습니다.

static anaylysis 툴에 대해 코드를 실행했을 때 Java 7에서 코드를 작성하는 더 좋은 방법이 있다고 생각하게하는 사소한 경고가있었습니다.

Might be better to replace use of get/check/put with putIfAbsent 

업데이트 : 그 하나 개의 스레드가 같은 준비된 문장을 만들려고하지 않는 경우에도 다른 차단할 수를 제외하고

public BoundStatement getStatement(String cql) { 
    Session session = TestUtils.getInstance().getSession(); 
    PreparedStatement ps = holder.get(cql); 
    // no statement is cached, create one and cache it now. 
    if (ps == null) { 
     ps = session.prepare(cql); 
     PreparedStatement old = holder.putIfAbsent(cql, ps); 
     if (old!=null) 
     ps=old; 
    } 
    return ps.bind(); 
    } 
+2

이 여러 가지 이유로 잘못되었습니다. 한 가지 예를 들어, 인스턴스를 동기화하여 정적 필드를 지키고 있습니다. 다른 하나는 동기화 및 잠금 해제 콜렉션을 혼합하는 것입니다. – shmosel

+0

접근 방식은 준비된 명령문 인스턴스를 캐싱 할 가치가 있다고 가정합니다. 그렇지? 매번 새로운 인스턴스를 생성 할 때 실제 성능에 미치는 영향은 무엇입니까? (진짜 질문, 나는 그들과 거의 거래하지 않으므로 헤비급인지 전혀 모른다.) –

+1

이 준비된 문을 캐시에 저장하지 않으면 모든 로그에 경고 메시지'이미 준비된 쿼리를 다시 준비 중입니다. 동일한 검색어를 두 번 이상 준비하는 것은 일반적으로 반 패턴이며 실적에 영향을 미칠 수 있습니다. 진술을 한 번만 준비해보십시오 .' datastax java driver에서. 여기에 [질문] (http://stackoverflow.com/questions/22915840/re-using-preparedstatement-when-using-datastax-cassandra-driver)이 더 자세히 설명되어 있으므로 준비된 문장을 다시 사용하기로 결정했습니다. . – john

답변

1

그것은, 당신이 그것을 가지고 너무 나쁘지 않다.

Java 8에서 computeIfAbsent을 사용하면 훨씬 더 좋습니다. 자바 7에서는이 작업을 수행 할 수 있습니다

ps = holder.get(cql); 
if (ps == null) { 
    ps = session.prepare(cql); 
    PreparedStatement old = holder.putIfAbsent(cql, ps); 
    if (old!=null) 
    ps=old; 
} 

두 스레드가 동시에 같은 일을 만들려고하는 경우가 가끔 있지만 캐시를 사용하지 않는 단지 동등의 최악의 경우, 불필요한 PreparedStatement로 만들 것 . 당신은 구아바 라이브러리를 사용할 수 있는지

또는 다음 구아바 LoadingCache은 당신이 원하는 정확히 무엇을 : https://google.github.io/guava/releases/16.0/api/docs/com/google/common/cache/CacheBuilder.html

+0

지금도'synchronized' 블록이 필요합니까? 아니면 그걸 없애고 putIfAbsent로 제안하는 것을 사용할 수 있습니까? – john

+0

동기화 된 블록이 필요하지 않습니다. –

+0

코드와 함께 질문을 업데이트했습니다. 그게 옳은 거니? 내가 제대로했는지 확인하는 것 뿐이야. – john

관련 문제