2012-02-10 2 views
2

질문 : 모니터가 이미 잠겨있을 때 동기화 된 블록을 다시 입력하는 비용은 얼마입니까? 예를 들어동기화 된 블록을 다시 입력하는 데 드는 비용

:

Object lock; 
void outer() 
{ 
    synchronized (lock) 
    { 
     innerOne(); 
     innerTwo(); 
    } 
} 

void innerOne() { synchronized (lock) { /* ... */ } } 
void innerTwo() { synchronized (lock) { /* ... */ } } 

위의 의도는 스레드가 lock에 동기화하는 동안 innerOneinnerTwo 항상 호출되는 것입니다.

무시할 수없는 비용이 있다면 assert 문을 넣기 위해 호출 할 수있는 방법이 있습니까? 가장 가까운 곳은 lock.notify()으로 전화하여 IllegalMonitorStateException을 잡는 것입니다.

boolean isMonitorHeld(final Object object) 
{ 
    try { object.notify(); return true } 
    catch (final IllegalMonitorStateException e) { return false; } 
} 
처럼 사용되는

:

void innerOne() { assert isMonitorHeld(lock); /* ... */ } 

이 두 가지 옵션의 스타일에 대한 의견, 또는 어떤 대안이 있습니까?

편집

난 그냥보다 더 포괄적 인 답변의 시간을 볼 '바라고 있어요. 필자는 코드에 발생할 수있는 모든 잠재적 상황을 미리 예상 할 수있는 능력이 없으며 이러한 상황을 나타 내기위한 테스트를 작성하기도합니다. 동기화 메커니즘이 다른 상황에서 어떻게 수행되는지 이해하는 방법을 이해하고 싶습니다. 동기화가 다른 플랫폼에서 다르게 구현 될 수 있음을 이해합니다. 어떤 경우에는 (주로 Solaris와 Linux OS에서) 다릅니 까?

직관적으로, 필자는 동기식 블록을 다시 입력하는 것이 발견 할 수있는 대부분의 기사가 비경쟁 잠금 장치가 싸다는 것을 암시한다고 생각하지 않습니다. 그러나 동기화에서 처음 동기화 된 없이는 이라고 할 수있는 인상을 주므로 동기화 된 블록을이 메서드에 추가하는 것이 옳다고 생각하지 않습니다. 단언은 의도에 대한 더 나은 아이디어를 제공하지만 상당히 못생긴 해킹처럼 보입니다. 더 합법적 인 대안이 없다는 좋은 이유가 있는지 알고 싶습니다.

+1

왜 측정하지 않습니까? 만약 당신이 * 차이를 측정 할 수 없다면 아무 것도 없다. – skaffman

답변

4

귀하의 질문에 한 가지만 묻는 경우 귀하의 질문 본문이 다른 것을 요구하고 있습니다. 스레드가 잠금을 유지하는지 테스트하는 알고리즘이 매우 느릴 것이라고 확실히 말할 수 있습니다. 검사하지 않는 것보다 훨씬 느립니다. 이런 예외를 던지는 것은 비싸다. 예외에 대한 규칙 1 번. 프로그램의 일반 흐름 제어에 예외를 사용하지 마십시오.. 예외 은 제어 흐름 구조 형식 인이지만 오류 흐름 제어에만 사용해야합니다. 주로 예외를 throw 할 때마다 예외에 배치하기 위해 스택 추적을 수집해야하기 때문입니다. 그것은 값 비싼 조작입니다. 예외를 사용해야하지만 오류 흐름 제어를 위해서만 사용해야합니다.

currentThread에 잠금이 있는지 확인하려면 Thread를 사용해야합니다.holdsLock (객체 모니터)

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#holdsLock(java.lang.Object)를 currentThread위한 동기화 블록으로 다시 들어가는 비용이 무엇인지에 대해서는

이미 홀더이다. 나는 그것에 대한 매우 상세한 대답을 가지고 있지 않다. 나는 그것이 무엇이든지 holdLock을 호출하는 비용이 무엇이든 의심한다. 아마도 이것이 첫 번째 검사 일 것입니다. false를 반환하면이 스레드를 요청하여이 객체 모니터에서 대기중인 스레드 목록에 추가하는 것이 더 많은 비용이 듭니다. 사실이라면 블록으로 바로 뛰어갑니다. 자바 쓰레딩, 퍼포먼스를 원한다면,이 질문에 대한 대답은 자물쇠 소유자에게 지옥처럼 빠르다. 잠금 장치를 소유하지 않은 스레드의 경우 확실히 더 비쌉니다. 정확한 알고리즘이 무엇인지에 대한 답이 있다면 나는 "Taming Threads"책이나 자바 스펙에 내기를 걸었습니다.

+0

고마워, 나는 Thread 메서드를 완전히 놓쳤다. 요점은 두 개 이상의 메소드 사이에 일부 공유 로직이 있다는 것입니다. 초기 메서드는 동기화를 제공하고 공유 논리가 실행됩니다. 내 경험에 따르면 어설 션은 개발자의 의도를 (코드로) 설명하는 데 유용합니다. 내 경우 실제로 모니터를 다시 동기화하면 처음에는 잠금을 얻지 않고 메서드를 호출 할 수 있다는 의미에서 잘못된 인상을줍니다. 이 메소드는 잠금을 먼저 얻지 않고 호출하면 안됩니다. 그렇다면 프로그래밍 오류입니다. – SimonC

+0

질문을 다시 읽었습니다. 코드의 첫 번째 섹션 에서처럼 잠금을 다시 얻는 대신이 두 메서드에서 assert 문을 사용할 수 있는지 알고 싶을뿐입니다. – chubbsondubs

+0

만약 메소드가 public이라면 나는하지 않을 것이지만 assert를 사용하는 private 메소드는 호출자가 lock하도록 강요 할 것이다. 그래서 누군가가 당신의 코드를 리팩토링한다면 lock을 잡는 것을 잊었을 때 catch 할 것이다. 동기화 된 블록을 사용하는 것과 동일한 방식으로 내기를하는 것이 현명 할 것입니다. – chubbsondubs

2

측정하십시오. 내 시스템에는 차이가 없을 수 있습니다. 거기에 네가 있을지도 몰라. 배포 할 시스템이 여전히 달라질 수 있습니다.

관련 문제