문제

Java에서는 코드에서 중요한 섹션을 선언하는 관용적 인 방법이 다음과 같습니다.

private void doSomething() {
  // thread-safe code
  synchronized(this) {
    // thread-unsafe code
  }
  // thread-safe code
}

거의 모든 블록이 동기화됩니다 this, 그러나 이것에 대한 특별한 이유가 있습니까? 다른 가능성이 있습니까? 동기화 할 객체에 대한 모범 사례가 있습니까? (예 : 개인 사례와 같은 Object?)

도움이 되었습니까?

해결책

먼저 다음 코드 스 니펫은 동일합니다.

public void foo() {
    synchronized (this) {
        // do something thread-safe
    }
}

그리고:

public synchronized void foo() {
    // do something thread-safe
}

하다 똑같은 것. 코드 가독성과 스타일을 제외하고 그들 중 하나를 선호하지 않습니다.

방법이나 코드 블록을 동기화하면 아는 것이 중요합니다. 당신은 그런 일을하고 있습니다 어떤 대상 정확히 당신은 잠금하고 있습니다 어떤 목적.

또한 원하는 상황이 있습니다. 클라이언트 측 동기화 당신이 요구하는 모니터가 (즉, 동기화 된 객체)가 반드시 필요한 코드 블록 this, 이 예에서와 같이 :

Vector v = getSomeGlobalVector();
synchronized (v) {
    // some thread-safe operation on the vector
}

동시 프로그래밍에 대한 더 많은 지식을 얻는 것이 좋습니다. 무대 뒤에서 무슨 일이 일어나고 있는지 정확히 알면 큰 도움이 될 것입니다. 체크 아웃해야합니다 자바의 동시 프로그래밍, 주제에 관한 훌륭한 책. 주제에 대한 빠른 다이빙을 원한다면 확인하십시오. Java 동시성 @ Sun

다른 팁

이전 답변자가 지적했듯이, 제한된 범위의 객체를 동기화하는 것이 가장 좋습니다 (즉, 도망 갈 수있는 가장 제한적인 범위를 선택하고 사용할 수 있습니다.) 특히 동기화 this 수업 사용자가 자물쇠를 얻지 못하게하지 않는 한 나쁜 생각입니다.

그러나 특히 추악한 경우가 발생합니다. java.lang.String. 줄은 (그리고 실제로 거의 항상) 인턴 될 수 있습니다. 즉, 동일한 컨텐츠의 각 문자열이 전체 JVM - 무대 뒤에서 같은 문자열로 밝혀졌습니다. 즉, 문자열에 동기화되면 동일한 콘텐츠가있는 문자열에서 잠그는 다른 (완전히 다른) 코드 섹션이 실제로 코드를 잠그는 것입니다.

한 번 생산 시스템에서 교착 상태를 문제 해결했고 (매우 고통스럽게) 교착 상태를 두 개의 완전히 이질적인 오픈 소스 패키지로 추적했습니다. "LOCK".

나는 동기화를 피하려고 노력합니다 this 그것은 그 개체를 언급 한 외부의 모든 사람이 내 동기화를 차단할 수있게 해주므로. 대신 로컬 동기화 객체를 만듭니다.

public class Foo {
    private final Object syncObject = new Object();
    …
}

이제 잠금을“도둑질”하는 것에 대한 두려움없이 해당 객체를 동기화에 사용할 수 있습니다.

java.util.concurrent.locks.readwritelock으로 발견 된 Java에서도 readwritelocks도 있습니다.

대부분의 사용에서 나는 '읽기'와 '업데이트 용'으로 잠금을 분리합니다. 동기화 된 키워드를 간단하게 사용하는 경우 동일한 메소드/코드 블록에 대한 모든 읽기가 '대기'됩니다. 한 번만 블록에 한 번만 액세스 할 수 있습니다.

대부분의 경우 단순히 독서를하는 경우 동시성 문제에 대해 걱정할 필요가 없습니다. 글쓰기를 할 때 동시 업데이트 (데이터 손실로 인해) 또는 걱정해야 할 쓰기 (부분 업데이트) 중에 걱정하는 것이 걱정됩니다.

따라서 읽기/쓰기 잠금은 멀티 스레드 프로그래밍 중에 나에게 더 의미가 있습니다.

뮤텍스 역할을 할 수있는 객체와 동기화하고 싶을 것입니다. 현재 인스턴스 인 경우 ( 이것 참조)는 적합합니다 (예 : 싱글 톤이 아님). Java에서는 모든 물체가 뮤 테스 역할을 할 수 있으므로 사용할 수 있습니다.

다른 경우에는 여러 클래스간에 뮤트를 공유 할 수 있습니다.이 클래스의 인스턴스가 모두 동일한 리소스에 액세스 해야하는 경우.

그것은 당신이 일하고있는 환경과 당신이 구축하는 시스템의 유형에 크게 의존합니다. 내가 본 대부분의 Java EE 애플리케이션에서는 실제로 동기화가 실제로 필요하지 않습니다 ...

개인적으로, 나는 그것이 결코 동기화하는 것이 결코 옳지 않다고 주장하는 답을 생각합니다. this 잘못 안내됩니다. 나는 그것이 당신의 API에 달려 있다고 생각합니다. 클래스가 SchredsAfe 구현이고 문서화하면 사용해야합니다. this. 동기화가 공개 메소드의 호출에서 클래스의 각 인스턴스를 전체 스레드 사프로 만드는 경우 개인 내부 객체를 사용해야합니다. 재사용 가능한 라이브러리 구성 요소 자주 이전 범주에 빠지십시오 - 사용자가 외부 동기화로 API를 랩핑하기 위해 사용자를 허용하지 않기 전에 신중하게 생각해야합니다.

전자의 경우 사용 this 원자 방식으로 여러 가지 방법을 호출 할 수 있습니다. 한 가지 예는 Printwriter입니다. 여기서 여러 줄 (콘솔/로거로의 스택 추적)을 출력하고 함께 나타나도록 보장 할 수 있습니다.이 경우 동기화 객체를 내부적으로 숨긴다는 사실은 진정한 고통입니다. 또 다른 예제는 동기화 된 컬렉션 포장지입니다. 그곳에서 반복하려면 컬렉션 객체 자체에 동기화해야합니다. 반복은 여러 메소드 호출로 구성되므로 귀하는 귀하가 구성됩니다 할 수 없습니다 완전히 내부적으로 보호하십시오.

후자의 경우, 나는 평범한 개체를 사용합니다.

private Object mutex=new Object();

그러나 잠금 장치가 "java.lang.object ()의 인스턴스"라고 말하는 많은 JVM 덤프와 스택 추적을 보았을 때 다른 사람들이 제안한 것처럼 내부 클래스를 사용하는 것이 더 도움이 될 수 있다고 말해야합니다.

어쨌든, 그것은 내 두 비트의 가치입니다.

편집 : 동기화 할 때 다른 한 가지 this 나는 방법을 동기화하고 방법을 매우 세분화하는 것을 선호합니다. 나는 그것이 더 명확하고 간결하다고 생각합니다.

Java의 동기화에는 종종 동일한 인스턴스의 동기화 작업이 포함됩니다. 동기화 this 그러면 그 이후로 매우 관용적입니다 this 클래스에서 다른 인스턴스 방법 (또는 섹션) 사이에 자동으로 사용할 수있는 공유 참조입니다.

개인 분야를 선언하고 초기화하여 잠금을 위해 특별히 다른 참조를 사용합니다. Object lock = new Object() 예를 들어, 내가 필요하지 않거나 사용하지 않은 것입니다. 객체 내부의 두 개 이상의 동기화되지 않은 리소스에 대한 외부 동기화가 필요할 때만 유용하지만 항상 그러한 상황을 더 간단한 형태로 리팩토링하려고합니다.

어쨌든, 암시 적 (동기화 된 방법) 또는 명시 적 synchronized(this) Java 라이브러리에서도 많이 사용됩니다. 그것은 좋은 관용구이며, 해당되는 경우 항상 첫 번째 선택 여야합니다.

동기화 된 내용에 따라이 메소드 호출과 충돌 할 수있는 다른 스레드가 동기화 될 수있는 것에 달려 있습니다.

만약에 this 하나의 스레드에서만 사용되는 객체이며 스레드간에 공유되는 변한 객체에 액세스하고 있습니다. 좋은 후보자는 해당 객체를 동기화하는 것입니다. this 공유 객체를 수정하는 다른 스레드 이후에는 아무런 의미가 없습니다. this, 그러나 그 대상을 알고 있습니다.

반면에 동기화 this 많은 스레드 가이 객체의 메소드를 동시에 호출하는 경우, 예를 들어 싱글 톤에있는 경우에 의미가 있습니다.

메소드가 실행되는 시간 내내 잠금을 고정하기 때문에 동시 화 된 방법은 종종 최선의 선택이 아닙니다. 시간이 소요되지만 스레드 안전 부품이 포함되어 있고 시간이 많이 걸리지 않은 스레드-미사일 부품이 포함되어 있으면 메소드를 동기화하는 것은 매우 잘못된 것입니다.

거의 모든 블록이 이것에 동기화되지만 이것에 대한 특별한 이유가 있습니까? 다른 가능성이 있습니까?

이 선언은 전체 메소드를 동기화합니다.

private synchronized void doSomething() {

이 선언은 전체 메소드 대신 코드 블록의 일부를 동기화했습니다.

private void doSomething() {
  // thread-safe code
  synchronized(this) {
    // thread-unsafe code
  }
  // thread-safe code
}

오라클 문서에서 페이지

이러한 방법을 동기화하는 데 두 가지 효과가 있습니다.

첫째, 동일한 객체에 동기화 된 메소드의 두 번의 호출이 불가능합니다.. 한 스레드가 객체에 대한 동기화 된 메소드를 실행하는 경우, 첫 번째 스레드가 객체로 완료 될 때까지 동일한 개체 블록 (SUSTNEND EXECUTION)에 대해 동기화 된 메소드를 호출하는 다른 모든 스레드.

다른 가능성이 있습니까? 동기화 할 객체에 대한 모범 사례가 있습니까? (예 : 개인의 대상 사례?)

동기화에 대한 많은 가능성과 대안이 있습니다. 높은 레벨 동시성을 사용하여 코드 스레드를 안전하게 만들 수 있습니다. 아피스(JDK 1.5 릴리스 이후 제공)

Lock objects
Executors
Concurrent collections
Atomic variables
ThreadLocalRandom

자세한 내용은 아래 SE 질문을 참조하십시오.

동기화 대 잠금

자바에서 동기화 (이것)을 피하십시오.

모범 사례는 잠금 장치를 제공하기 위해 객체 만 만드는 것입니다.

private final Object lock = new Object();

private void doSomething() {
  // thread-safe code
  synchronized(lock) {
    // thread-unsafe code
  }
  // thread-safe code
}

이렇게함으로써 당신은 안전합니다. 통화 코드가 의도하지 않은 사람에 의해 당신의 방법을 교착시킬 수 있습니다. synchronized(yourObject) 선.

(@jared 및 @yuval-adam에 대한 크레딧은 위의 자세한 내용으로 이것을 설명했습니다.)

제 생각에는 사용의 인기가 있습니다 this 튜토리얼에서 초기 Sun Javadoc에서 나왔습니다. https://docs.oracle.com/javase/tutorial/estential/concurrency/locksync.html

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top