다른 동기화 된 메서드에서 동기화 된 메서드를 호출하는 것이 안전합니까?


81

동기화 된 메서드가 다른 동기화 된 메서드를 호출하는 경우 스레드로부터 안전합니까?

void synchronized method1() {
     method2()
}

void synchronized method2() {
}

이 기사가 답을 찾는 데 도움이됩니까? 아니면 어디에서 헷갈 리십니까? kalyanchakravarthy.net/?p=413
James Black

예-위에서 주어진 컨텍스트에서만 호출된다는 가정하에 method2를 동기화 된 것으로 표시 할 필요는 없습니다.
debracey 2011

4
또한 스레드 안전 여부는 두 가지 방법에서 발생하는 일에 따라 달라집니다. 예를 들어 스레드 세이프가 아닌 목록을 호출하면 다른 스레드가 해당 컬렉션을 수정할 수 있다면 스레드 세이프가 아닐 수 있습니다.
James Black

내가 추측하는 것에 대한 대답은 실제 질문입니다. 예, 동기화 된 키워드는 재귀 잠금을 사용합니다. 다른 동기화 된 메서드에서 동기화 된 메서드를 안전하게 호출 할 수 있습니다.
Brett Kail 2011

오랜 시간이 지났지 만 여전히 Google에서 첫 번째 히트작이므로 동일한 객체에 대한 동기화 된 블록 / 메서드가 재진입됩니다. stackoverflow.com/questions/12219376/reentrant-synchronization
Szocske

답변:


103

예, 메소드를으로 표시 synchronized하면 실제로 다음을 수행하는 것입니다.

void method1() {
    synchronized (this) {
        method2()
    }
}

void method2() {
    synchronized (this) {
    }
}

스레드 호출이 method1에서 method2로 들어가면 잠금을 this 이미 한 다음 통과 할 수 .

스레드가 method1 또는 method2로 직접 들어가면 잠금 ( this)을 얻을 수있을 때까지 차단 된 다음 들어갑니다.

James Black이 주석에서 언급했듯이 메서드 본문 내에서 수행하는 작업에 대해 알고 있어야합니다.

private final List<T> data = new ArrayList<T>();

public synchronized void method1() {
    for (T item : data) {
        // ..
    }
}

public void method3() {
    data.clear();
}

비 동기화되어 스레드 B가에서 작업하는 동안 스레드 A가 호출 할 수 ConcurrentModificationException있기 때문에 미래 에 a 를 보고 있기 때문에 갑자기 스레드로부터 안전하지 않습니다 .method3method1


여기에서 질문 한 것과 거의 동일한 질문에 대답하려고합니다. 다음은 2 개의 가능한 답변입니다 (다른 2 개는 실행되지 않는다고 말합니다). 어느 것이 맞습니까? C. 코드가 실행되지만 잠재적 인 교착 상태 상황이 있습니다. D. Java가 재진입 동기화를 제공하므로 스레드가 동일한 잠금을 두 번 이상 획득 할 수 있으므로 코드가 정상적으로 실행됩니다. ----- D라고 생각하지만 아마도 잠재적 교착 상태 상황은 메서드 본문에 따라 달라집니다.

@ user3140993 여기의 코드는 교착 상태가 될 가능성이 없습니다. method3안전하지 않은 스레딩 작업을 보여 주지만 재진입 동기화에 대해 주목하고 있습니다.
pickypg jul.

7

동기화 된 호출 다른 동기화 된 메서드 스레드로부터 안전한 것으로 표시된 메서드입니다.

일반적으로 말할 수 없습니다. 메서드가 수행하는 작업과 동일한 클래스 및 다른 클래스의 다른 메서드가 수행하는 작업에 따라 다릅니다.

그러나 다른 스레드에서 만든 동일한 객체에 대한 method1 및 method2에 대한 호출이 동시에 실행되지 않도록 할 수 있습니다. 메서드가 수행하는 작업에 따라 클래스가 이러한 메서드와 관련하여 스레드로부터 안전하다고 말하기에 충분할 있습니다.


2

Java Tutorials 사이트 http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html에서

  1. 동일한 개체에서 동기화 된 메서드를 두 번 호출하는 것은 인터리브 할 수 없습니다. 한 스레드가 개체에 대해 동기화 된 메서드를 실행할 때 첫 번째 스레드가 개체에 대해 완료 될 때까지 동일한 개체 블록에 대해 동기화 된 메서드를 호출하는 다른 모든 스레드 (실행 일시 중지)입니다.

  2. 동기화 된 메서드가 종료되면 동일한 개체에 대한 동기화 된 메서드의 후속 호출과 사전 발생 관계를 자동으로 설정합니다. 이렇게하면 개체의 상태 변경 사항이 모든 스레드에 표시됩니다.

따라서 Java는 두 스레드가 동일한 메서드를 실행하는 경우 메서드가 동시에 실행되지 않고 차례로 실행되도록합니다.

하지만 Liveness 문제를 알고 있어야합니다. http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html

또한 불필요하게 잠그고 있는지 여부에 관계없이 전체 객체를 잠그는 코드에서 this 를 사용 하여 객체가 하나의 변수에 대한 동기화 액세스 만 필요하면 해당 변수를 잠 가야합니다.


@Stephen Lee-변수를 잠글 수 없습니다. 그런 다음 synchronized (this.someVar)참조가에서 유지되는 객체를보고 있다고 말합니다 someVar. 구별은 매우 중요합니다.
Stephen C
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.