Java 동기화 정적 메소드 : 오브젝트 또는 클래스 잠금


148

자바 문서는 말합니다 :

동일한 오브젝트에서 동기화 된 메소드를 두 번 호출하여 인터리브 할 수 없습니다.

정적 메소드의 의미는 무엇입니까? 정적 메서드에는 연결된 개체가 없으므로 동기화 된 키워드가 개체 대신 클래스에서 잠깁니까?

답변:


129

정적 메서드에는 연결된 개체가 없으므로 동기화 된 키워드가 개체 대신 클래스에서 잠깁니까?

예. :)


81
모든 사람이 이해할 수 있도록 정교하게 대답하십시오.
Madhu September

6
@Madhu. 즉, 같은 클래스에 둘 이상의 동기화 된 메소드가있는 경우 해당 클래스의 인스턴스가 여러 개인 경우에도 둘 다 동시에 실행할 수 없습니다. 잠금은 본질적으로 동기화 된 각 메소드에 대한 Object.class의 잠금과 동일합니다.
Steven

이 답변은 잘못되었습니다- this인스턴스 메소드에서 얻은 잠금입니다. Oscar를 수정하십시오.
vemv

1
@vemv 문제는 인스턴스 메소드가 아니라 클래스 메소드에 관한 것입니다.
OscarRyz

23
@vemv 글쎄, 대답을 이해하려면 먼저 질문을 읽어야합니다.
OscarRyz

199

Oscar의 답변에 약간의 세부 사항을 추가하기 위해 Java 언어 사양의 관련 섹션은 8.4.3.6, '동기화 방법'입니다 .

동기화 된 방법은 모니터 가 실행되기 전에 ( §17.1 ) 획득합니다 . 클래스 (정적) 메소드의 경우 메소드 클래스의 클래스 오브젝트와 연관된 모니터가 사용됩니다. 인스턴스 메소드의 경우, 이와 연관된 모니터 (메소드가 호출 된 오브젝트)가 사용됩니다.


17
유용합니다, 저는 그 견적 +1을 찾고있었습니다
OscarRyz

80

주의해야 할 한 가지 점은 (여러 프로그래머가 일반적으로 해당 트랩에 속함) 동기화 된 정적 메소드와 동기화 된 비 정적 메소드 사이에 링크가 없다는 것입니다.

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

본관:

A a = new A();

실 1 :

A.f();

실 2 :

a.g();

f ()와 g ()는 서로 동기화되지 않으므로 완전히 동시에 실행할 수 있습니다.


18
그러나 g ()가 f ()가 읽는 정적 변수를 변경하면 어떻게됩니까? 이 스레드를 어떻게 안전하게 만들 수 있습니까? 그러면 클래스에 대한 잠금을 명시 적으로 얻습니까?
baskin

22
예, 정적이 아닌 메소드는 클래스 자체에서 명시 적으로 동기화해야합니다 (예 : synchronized (MyClass.class) {...}.
jfpoilpret

@jfpoilpret "synchronized (MyClass.class) {...}"는이 메소드를 정적으로 동기화시키는 것과 같습니다.
crazymind

15

다음과 같이 g ()를 구현하지 않는 한 :

g() {
    synchronized(getClass()) {
        ...
    }
}

이 패턴은 객체의 다른 인스턴스간에 상호 배제를 구현하려는 경우에도 유용합니다 (예 : 외부 리소스에 액세스 할 때 필요함).


63
실제로 여기에는 매우 미묘하고 불쾌한 버그가있을 수 있습니다. Remember getClass()런타임 유형을 리턴합니다 . 클래스를 서브 클래스로 만들면 부모 클래스와 자식 클래스가 다른 잠금에서 동기화됩니다. synchronized(MyClass.class)모든 인스턴스가 동일한 잠금을 사용하도록해야하는 경우가는 방법입니다.
Cowan

4

내장 잠금 및 동기화 에 대한 Oracle 설명서 페이지를 살펴보십시오

정적 메소드가 오브젝트가 아닌 클래스와 연관되어 있기 때문에 정적 동기화 메소드가 호출 될 때 어떤 일이 발생하는지 궁금 할 것입니다. 이 경우 스레드는 class와 연관된 Class 객체에 대한 고유 잠금을 획득합니다 . 따라서 클래스의 정적 필드에 대한 액세스는 클래스의 모든 인스턴스에 대한 잠금과 다른 잠금에 의해 제어됩니다 .


2

정적 메서드에는 관련 개체도 있습니다. JDK 툴킷의 Class.class 파일에 속합니다. .class 파일이 램에로드되면 Class.class는 템플릿 객체라는 파일의 인스턴스를 만듭니다.

예 :-기존 고객 클래스에서 객체를 만들려고 할 때

Customer c = new Customer();

Customer.class는 RAM으로로드됩니다. 이때 JDK 툴킷의 Class.class는 Template 객체라는 객체를 생성하고 해당 Customer.class를 해당 템플릿 객체에로드합니다. 해당 Customer.class의 정적 멤버는 해당 템플릿 객체의 속성과 메소드가됩니다.

따라서 정적 메소드 또는 속성에도 객체가 있습니다


2

아래 예제는 클래스와 객체 잠금을 더 명확하게 보여줍니다. 아래 예제는 다른 사람들에게도 도움이되기를 바랍니다. :)

예를 들어 아래의 메소드 중 하나는 acquire 클래스와 다른 acquire 객체 잠금입니다.

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

이제 우리는 다음과 같은 시나리오를 가질 수 있습니다.

  1. 동일한 객체를 사용하는 스레드 가 objLock OR staticLock 메소드에 동시에 액세스하려고 할 때 (즉, 두 스레드가 동일한 메소드에 액세스하려고 시도하는 경우)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  2. 사용하여 스레드 때 동일한 개체 에 액세스하려고 staticLockobjLock방법 동시에 (시도는 다른 방법을 접근)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
  3. 다른 객체를 사용하는 스레드 가 staticLock메소드 에 액세스하려고 할 때

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  4. 다른 객체를 사용하는 스레드 가 objLock메소드 에 액세스하려고 할 때

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4

0

클래스 객체에 고정 된 정적 동기화 메소드에 익숙하지 않은 사람들을 위해 (예 : 문자열 클래스의 경우 String.class) 인스턴스 동기화 메소드는 Java에서 "this"키워드로 표시되는 Object의 현재 인스턴스에서 잠 깁니다. 이 두 객체가 다르기 때문에 잠금이 다르기 때문에 한 스레드가 정적 동기화 메소드를 실행하는 동안 java의 다른 스레드는 해당 스레드가 반환 될 때까지 기다릴 필요가 없습니다. 대신 byte .class 리터럴로 표시된 별도의 잠금을 획득하고 입력하십시오. 정적 동기화 방법.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.