문제

CheckStyle 은이 코드를 "두 번 확인 된 잠금 관용구가 깨졌다"고보고하지만, 내 코드는 실제로 이중 체크 고정 문제의 영향을받는다고 생각하지 않습니다.

해당 ID가있는 행이 존재하지 않으면 코드는 데이터베이스에 행을 생성해야합니다. 다중 스레드 환경에서 실행되며 기본 키에 실증 된 SQL-Exceptions를 피하고 싶습니다.

의사 코드 :

private void createRow(int id) {
  Row row = dao().fetch(id);
  if (row == null) {
     synchronized (TestClass.class) {
        row = dao().fetch(id);
        if (row == null) {
           dao().create(id);
        }
     }
  }
}

이중 체크 잠금처럼 보이지만 정적 변수를 사용하지 않으며 fetch ()의 코드를 사용하지 않고 Create ()가 너무 복잡하여 내려 가서 주문을 중단 할 수 없습니다.

내가 틀렸습니까 아니면 체크 스타일입니까? :)

도움이 되었습니까?

해결책

가장 안쪽 줄을 읽기를 원한다고 가정합니다.

row = dao().create(id);

전형적인 이중 확인 잠금 문제가 아닙니다 dao().fetch 생성 메소드에서 올바르게 뮤 테이 링됩니다.

편집하다: (코드가 업데이트 됨)

두 개의 스레드가 동일한 값에 액세스하는 경우 초기화가 발생하기 전에 이중 확인 잠금의 고전적인 문제는 할당 된 값을 갖는 것입니다.

DAO가 올바르게 동기화되어 부분적으로 초기화 된 값을 반환하지 않는다고 가정하면, 이는 이중 확인 된 잠금식 관용구의 결함으로 어려움을 겪지 않습니다.

다른 팁

이 경우 CheckStyle이 정확하다고 생각합니다. 제시된 코드에서 두 스레드가 두 스레드가 있으면 어떻게 될지 고려하십시오. row == null 동기화 된 블록 입력시. 스레드 A는 블록에 들어가서 새 행을 삽입합니다. 그런 다음 스레드 A가 블록을 종료 한 후 스레드 B가 블록에 들어가고 (방금 일어난 일을 알지 못하기 때문에) 동일한 새 행을 다시 삽입하려고합니다.

나는 당신이 방금 코드를 변경하고 거기에 매우 중요한 누락 된 라인을 추가 한 것을 본다. 에서 새로운 코드는 두 스레드가 공유 (static) 변수의 변경에 의존하지 않기 때문에이를 벗어날 수 있습니다. 그러나 DBMS가 다음과 같은 진술을 지원하는지 보는 것이 더 나을 수도 있습니다. INSERT OR UPDATE.

이 기능을 DBMS에 위임하는 또 다른 이유는 둘 이상의 애플리케이션 서버를 배포 해야하는 경우입니다. 부터 synchronized 블록은 기계에서 작동하지 않으므로 어쨌든이 경우 다른 작업을 수행해야합니다.

이와 같은 코드를 작성하려는 유혹이 있다면 다음을 고려하십시오.

  • Java 1.4 이후 동기화 방법은 꽤 저렴 해졌습니다. 무료는 아니지만 런타임은 실제로 데이터 손상 위험을 위험에 빠뜨리는 것이 가치가 없습니다.

  • Java 1.5 이후 원자력* 클래스가있어 원자 방식으로 필드를 읽고 설정할 수 있습니다. 불행히도, 그들은 당신의 문제를 해결하지 않습니다. 그들이 원자 교정 회의를 추가하지 않은 이유 나 (get ()가 호출되고 현재 값 == null)가 나와 함께하는 경우 우선적 인 방법을 호출 할 수있는 이유가 나머지입니다.

  • 노력하다 ehcache. 캐시를 설정할 수 있습니다 (예 : 키가있는 경우 코드를 호출 할 수있는 객체 ~ 아니다 지도에 포함). 이것은 일반적으로 당신이 원하는 것이며 캐시는 실제로 당신의 문제를 해결합니다 (그리고 당신이 몰랐던 다른 모든 문제가 존재했다는 것).

다른 사람들이 지적했듯이,이 코드는 당신이 의도 한 바를 수행 할 것이지만, 엄격한 비만적 인 가정하에 있습니다.

  1. Java 코드는 클러스터되지 않았습니다 (@Greg h의 답변 참조)
  2. "행"참조는입니다 동기화 블록 전에 첫 번째 줄에서 NULL을 점검합니다.

이중 확인 된 잠금 관용구가 깨진 이유 (섹션 16.2.4에 따라 실제로 Java 동시성)이 메소드를 실행하는 스레드가 널이 아닌 것을 볼 수 있지만 부적절하게 초기화되었습니다 동기화 된 블록을 입력하기 전에 "행"에 대한 참조 ( "dao"가 적절한 동기화를 제공하지 않는 한). 당신의 방법이 null인지 아닌지 확인하는 것 외에 다른 "행"으로 무엇이든하고 있다면, 그것은 깨질 것입니다. 그것이 서 있듯이, 아마 괜찮을 것입니다 매우 깨지기 쉬운 - 개인적으로 나중에 다른 개발자가 DCL의 미묘함을 이해하지 않고 방법을 수정할 수있는 원격 기회가 있다고 생각되면이 코드를 저지르는 것이 편하지 않을 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top