문제

Java 동기화에 대해 논의하는 동안 의문, 누군가는 다음 스 니펫이 동등하지 않으며 (다른 바이트 코드로 컴파일 할 수 있음) 의견을 제시했습니다.

public synchronized void someMethod() {
  //stuff
}

그리고

public void someMethod() {
  synchronized (this) {
    //stuff
  }
}

그들은 동등합니까?

도움이 되었습니까?

해결책

내가 테스트 한 컴파일러 (Java 1.6.0_07 및 Eclipse 3.4)는 다른 바이트 코드를 생성하지만 기능이 동일합니다. 첫 번째 생성 :

// access flags 33
public synchronized someMethod()V
  RETURN

두 번째는 다음과 같습니다.

// access flags 1
public someMethod()V
  ALOAD 0
  DUP
  MONITORENTER
  MONITOREXIT
  RETURN

(감사합니다 ASM 바이트 코드 인쇄의 경우).

따라서 그들 사이의 차이는 바이트 코드 수준으로 지속되며 행동을 동일하게 만드는 것은 JVM에 달려 있습니다. 그러나 동일한 기능 효과가 있습니다. 예시 Java 언어 사양에서.

메소드가 서브 클래스로 무시되면 반드시 동기화되지는 않으므로 그와 관련하여 차이가 없습니다.

또한 각 경우에 모니터에 액세스하려고 시도하는 스레드를 차단하기 위해 테스트를 실행하여 스레드 덤프에서 스택 추적이 어떻게 보일지 비교했으며 문제의 메소드가 포함되어 있으므로 차이가 없습니다.

다른 팁

나는 진술이 동일하다는 원래의 의견을 만들었습니다.

두 경우 모두 가장 먼저 발생하는 일은 호출 스레드가 현재 객체 (의미, 의미, this') 모니터.

나는 다른 바이트 코드에 대해 모른다. 나는 그 차이를 듣고 기뻐할 것이다. 그러나 실제로는 100% 동일합니다.

편집하다: 여기 사람들이 잘못 되었기 때문에 이것을 명확히 할 것입니다. 고려하다:

public class A {
    public synchronized void doStuff()
    {
        // do stuff
    }
}

public class B extends A {
    public void doStuff()
    {
        // do stuff
        // THIS IS OVERRIDE!
    }
}

이 경우 doStuff() 클래스 B에서 여전히 무시합니다 doStuff() 클래스 A에서는 동기화되지 않더라도.

동기화 된 키워드는 계약의 일부가 아닙니다! 서브 클래스의 경우, 인터페이스가 아니라 추상 클래스가 아닙니다.

나는 원래 의견을했다. 내 의견은 논리적으로 동등하지만 다른 바이트 코드로 컴파일합니다.

나는 실제로 정당화 할 것이 많지 않기 때문에 당시에는 그것을 정당화하기 위해 다른 것을 추가하지 않았습니다. 하다 다른 바이트 코드로 컴파일합니다. 방법을 다음과 같이 선언하는 경우 동기화, 그런 다음 동기화는 메소드 정의의 일부입니다. 방법 내의 동기화 된 블록 그렇지 않습니다 방법의 정의의 일부, 위의 포스터 중 하나가 설명했듯이 모니터를 획득하고 해제하기 위해 별도의 바이트 코드가 포함됩니다. 그러나 엄격하게 말하면, 그들은 약간 다른 것입니다 ~로 프로그램의 전반적인 논리, 그들은 동등합니다.

이것은 언제 중요합니까? 글쎄, 대부분의 현대적인 데스크탑 VM에서는 거의 없습니다. 그러나 예를 들어 :

  • VM은 원칙적으로 한 경우에 최적화를 만들 수 있지만 다른 경우에는
  • 어디에 JIT 컴파일러 최적화가 있습니다 이 방법의 바이트 코드 수는 어떤 최적화가 만들어야하는지에 대한 기준으로 간주됩니다.
  • VM 없이 JIT 컴파일러 (요즘에는 거의 없지만 오래된 모바일 장치에서?)는 각 호출마다 처리 할 더 많은 바이트 코드가 있습니다.

예. 인스턴스 메소드에서 동기화 된 키워드를 사용하면 'this'를 모니터로 사용하면 클래스 메소드 (static method)에서이를 사용하면 클래스 클래스 객체 (foo.class)를 사용합니다.

이렇게하면 전체 메소드를 동기화하고 동시에 동기화 된 블록 스타일을 사용하여 다른 방법으로 코드 스 니펫과 동기화 할 수 있습니다.

기능적 차이를 볼 수 없습니다. 둘 다 전체 메소드 본문을 (this) 동기화합니다. 이것들이 다른 사람이 자신의 진술을 어떻게 정당화했다고 언급 한 사람은 어떻게 했습니까?

그들은 기능이 그다지 동등하지 않습니다. 다른 코드는 반사를 사용하여 메소드에 동기화 된 수정자가 있는지 확인할 수 있지만, 메소드에 바이트 코드를 읽지 않고 동기화 된 블록이 포함되어 있는지 알 수있는 방법은 없습니다.

메소드가 때때로 동기화되는지 확인하는 기능은 유용합니다. 개인적으로, 나는 그 깃발을 사용하여 종자 지향 프로그래밍에서 동기화 할 때 중복 잠금을 피했습니다.

MyObject myObjectA;
MyObject myObjectB;

public void someMethod() {
  synchronized (this) {
    //stuff
  }
}

public void someMethodA() {
  synchronized (myObjectA) {
    //stuff
  }
}

public void someMethodB() {
  synchronized (myObjectB) {
    //stuff
  }
}

이 경우 :

  • someMethod 전체 클래스를 차단합니다
  • someMethodA 블록 myObjectA
  • someMethodB 블록 myObjectB
  • someMethodA 그리고 someMethodB 동시에 호출 할 수 있습니다
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top