2010-08-11 5 views
2

나는 다음의 3 가지 경우를 취함으로써이 질문을 설명하려고 노력할 것이다. CASE I를 : 나는이 같은 것을 사용하여 동기화를위한 공유 잠금을 사용했다 :동기화를 위해 공유 잠금 대신 로컬 잠금을 사용하는 것이 안전합니까?


     private static final String SHARED_LOCK = "shared_lock"; 
     private static int i = 0; 
     private static int j = 0; 
    void increment() { 
     synchronized (SHARED_LOCK) { 
      i++; 
      j++; 
     } 
    } 

그리고 그것은 잘 작동된다.

CASE II : 여기 변경 대신 내가 이런 일을 수행하여 지역 잠금을 사용하여 생각을 공유 잠금 사용하다 한 이제 무엇을 :


     private static int i = 0; 
     private static int j = 0; 
    void increment() { 
     final String LOCAL_LOCK = "local_lock"; 
        synchronized (LOCAL_LOCK) { 
      i++; 
      j++; 
     } 
    } 

을 그리고 그 코드는 여전히 잘 작동되었다 발견 동기화가 여전히 작동하고 있습니다.

CASE III : 나는 로컬 locl을 변경하지만 이에는 :

final String LOCAL_LOCK = new String("local_lock");

다음 동기화 멀리 갔다. 따라서 CASE II에서 로컬 잠금은 자바가 자동으로 처리하는 String 리터럴을 지원하기 때문에 동기화를 제공 할 수 있지만 CASE III에서는 매번 새로운 String을 명시 적으로 생성하므로 동기화가 발생하지 않는 것처럼 보입니다.

그래서 내 원래의 질문으로 돌아갑니다. 누구나 사례 2가 동기화를 달성하는 올바른 방법이 아니라고 생각합니까? 그렇다면 이유를 말씀해주십시오.

미리 감사드립니다. SacTiw.

답변

3

여기에서 아주 중요한 것은 'canonicalizable'객체를 사용한다는 것입니다 객체를 다른 클래스로 잠급니다.

이것은 상상하는 바와 같이 매우 나쁜 생각입니다. 다른 클래스와 동일한 잠금을 사용하면 앱이 교착 상태에 빠지는 이유를 직접 연습하고 시도하면서 근본적으로 고통스러운 디버깅 전체를 보장 할 수 있습니다.

클래스에 비공개 잠금이 필요한 경우 new 연산자를 통해서만 가져와 완전히 고유 한 개체인지 확인하십시오.

는 (나는이 덮여 수도 자바 퍼즐 러 (Puzzler) 발표 한 생각, 다른 예를 참조 herehere 있습니다) 인턴에 대한

+0

그래서 여기서는 case-2가 다른 클래스에 액세스하는 다른 스레드가이 클래스와 동일한 잠금을 사용하기 시작하여 성능이 좋지 않고 디버깅이 어려울 수 있음을 의미합니다. 권리? – sactiw

+0

Java Language Specification에서는 Java에서 리터럴 문자열 (불변)이 다른 패키지의 다른 클래스에 있으면서 같은 String 객체에 대한 참조를 나타냅니다. 그리고이 규칙은 모든 원시 객체에도 적용됩니다. 모든 원시 객체는 모두 불변입니다. 그렇다면 case-2로 진행하면 교착 상태가 발생할 경우 성능이 좋지 않고 디버깅이 어려울 수 있습니다. 그래서 우리는 동기화가 내 질문에 case-2를 통해 가능하다고 말할 수 있다고 생각하지만 사용하는 것은 전혀 권장되지 않습니다. – sactiw

+0

물론 그렇습니다. 비공개로 액세스 할 수없는 다른 클래스의 Object를 사용하는 것 외의 것을 사용하는 것은 대개 매우 나쁜 생각입니다. 'new'를 통해 객체를 얻는다면, 당신과 당신 만의 객체라는 것을 알 수 있습니다 (당신이 그것을 유출하지 않는다면). – Cowan

8

잠금은 별도의 스레드에서 실행되는 코드간에 동기화를 제공하기위한 것입니다. 로컬 락을 사용하는 경우, 각 thread는 자물쇠를 걸 예정인 락 오브젝트의 독자적인 카피를 (thread의 스택 내에) 가지므로, 동기는 없습니다.

String internation 때문에 당신의 경우에만 작동합니다. final Object LOCAL_LOCK = new Object();을 사용하면 작동하지 않습니다.

그래서 잠금은 항상 스레드간에 공유되어야합니다.

+0

일을. 하나는'increment()'에 대한 각 호출이 로컬 변수이므로 자체 잠금을 가질 것으로 기대합니다. VM이 동일한 텍스트가있는 모든 변수에 대해 동일한'String' 인스턴스를 사용하기 때문에'String' 사용은이 경우 전문입니다 (동기화가 예기치 않게 작동하게 함). 자세한 내용은 http://en.wikipedia.org/wiki/String_interning을 참조하십시오. – f1sh

+0

나는 case-II가 잘 동작하는 이유를 안다. 필자는 이미 Java가 수행 한 String의 자동 인터 about팅에 대해 언급 한 바 있습니다. 또한 각 스레드가 자체 잠금 버전을 갖기 때문에 case-III가 실패하는 이유를 알기 때문에 스레드가 완료 될 때까지 기다립니다. 그래서 내가 알고 싶어했던 것은 동기화를 위해 case-II를 사용하는 것이 정말로 안전한지 또는 후자가 발생할 수있는 case II에 숨겨진 문제가 있는지 여부였습니다. – sactiw

+0

@sactiw : 항상 인턴 된 문자열을 잠금으로 사용하려고한다면 괜찮을 것입니다. 하지만 언젠가 누군가가 String을 다른 유형으로 변경할 수 있고 모든 것이 신비하게 실패 할 것이기 때문에 여전히 나쁜 습관입니다. –

1

문자열 인턴 때문에. 동일한 값을 갖는 사례 2에서 생성 된 모든 문자열은 동일한 인스턴스를 '공유'합니다. 사례 3에서와 같이 생성 된 문자열은 별개의 인스턴스가됩니다.

다른 동기화 동작을 설명하는 차이점이 있습니다.

4

동기화는 스레드간에 동일한 개체를 동기화하는 경우에만 올바르게 작동합니다.

  • 제 1 회 사건은 분명하다, 두 번째 경우
  • 자바 컴파일러 인턴 문자열 상수있는
  • 제 1, 너무 작동 왜 (당신이 통화 사이의 문자열 풀에서 동일한 개체를 얻을 수)입니다 세 번째 경우에는 새 문자열 객체를 강제로 처리하므로 스레드 당 사용자 고유의 개인용 잠금이 발생하여 동기화가 전혀 수행되지 않습니다.구금 할 수 있습니다 말처럼, String의, 또는 공유 할 수 있습니다 Integer 상수 - - 기본적으로 동일한를 사용하여 당신을 열고있다
관련 문제