여러 스레드가 클래스 필드에 안전하게 액세스할 수 있도록 어떻게 보장합니까?

StackOverflow https://stackoverflow.com/questions/118371

문제

여러 스레드가 getter 메서드를 통해 클래스 필드에 액세스하는 경우 스레드 안전성을 어떻게 유지합니까?동기화된 키워드로 충분합니까?

안전한가요?

public class SomeClass {
    private int val;

    public synchronized int getVal() {
        return val;
    }

    private void setVal(int val) {
        this.val = val;
    }
}

아니면 세터가 더 복잡한 문제를 야기합니까?

도움이 되었습니까?

해결책

여기에서도 setter에 'synchronized'를 사용한다면 이 코드는 스레드로부터 안전합니다.그러나 충분히 세분화되지 않을 수도 있습니다.20개의 getter 및 setter가 있고 모두 동기화된 경우 동기화 병목 현상이 발생할 수 있습니다.

이 특정 인스턴스에서는 단일 int 변수를 사용하여 'synchronized'를 제거하고 int 필드를 '휘발성'으로 표시하면 가시성이 보장되지만(각 스레드는 getter를 호출할 때 'val'의 최신 값을 볼 수 있음) 그렇지 않을 수도 있습니다. 귀하의 필요에 맞게 충분히 동기화하십시오.예를 들어, 기대

 int old = someThing.getVal();
 if (old == 1) {
    someThing.setVal(2);
 }

val을 2로 설정하는 것은 이미 1인 경우에만 올바르지 않습니다.이를 위해서는 외부 잠금이나 일부 원자 비교 및 ​​설정 방법이 필요합니다.

꼭 읽어보시길 권합니다 실제로 Java 동시성 브라이언 괴츠 , 이는 Java의 동시성 구성을 가장 잘 포괄합니다.

다른 팁

게다가 코완의 코멘트, 비교 및 ​​저장을 위해 다음을 수행할 수 있습니다.

synchronized(someThing) {
    int old = someThing.getVal();
    if (old == 1) {
        someThing.setVal(2);
    }
}

이는 동기화된 메서드를 통해 정의된 잠금이 객체의 잠금(자바 언어 사양을 참조하세요).

내가 이해한 바로는 getter와 setter 메서드 모두에 동기화를 사용해야 하며, 그것으로 충분합니다.

편집하다:여기에는 링크 동기화에 대한 추가 정보와 그렇지 않은 정보.

클래스에 변수가 하나만 포함된 경우 스레드 안전성을 달성하는 또 다른 방법은 기존 AtomicInteger 개체를 사용하는 것입니다.

public class ThreadSafeSomeClass {

    private final AtomicInteger value = new AtomicInteger(0);

    public void setValue(int x){
         value.set(x);
    }

    public int getValue(){
         return value.get();
    }

}

그러나 종속적(한 변수의 상태가 다른 변수의 상태에 따라 다름)과 같은 추가 변수를 추가하면 AtomicInteger가 작동하지 않습니다.

"Java Concurrency in Practice"를 읽으라는 제안을 반영합니다.

단순한 객체의 경우 이것으로 충분할 수 있습니다.대부분의 경우 동기화 교착 상태가 발생할 수 있으므로 동기화 키워드를 사용하지 않는 것이 좋습니다.

예:

public class SomeClass {

  private Object mutex = new Object();
  private int    val   = -1; // TODO: Adjust initialization to a reasonable start
                             //       value
  public int getVal() {
    synchronized ( mutex ) {
      return val;
    }
  }

  private void setVal( int val ) {
    synchronized ( mutex ) {
      this.val = val;
    }
  }
}

하나의 스레드만 로컬 인스턴스 멤버를 읽거나 쓰도록 보장합니다.

"Java(tm)의 동시 프로그래밍:디자인 원리 및 패턴(Java(Addison-Wesley))", 어쩌면 http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html 도 도움이 됩니다...

스레드 간섭 및 메모리 일관성 오류로부터 보호하기 위해 동기화가 존재합니다.getVal()을 동기화함으로써 코드는 SomeClass의 다른 동기화된 메소드도 동시에 실행되지 않도록 보장합니다.다른 동기화 방법이 없기 때문에 많은 가치를 제공하지 않습니다.또한 기본 요소에 대한 읽기 및 쓰기에는 원자성 액세스가 있습니다.즉, 신중하게 프로그래밍하면 필드에 대한 액세스를 동기화할 필요가 없습니다.

읽다 동기화.

왜 이것이 -3으로 떨어졌는지 잘 모르겠습니다.나는 Sun의 동기화 튜토리얼(그리고 내 경험)을 간단히 요약하고 있습니다.

간단한 원자 변수 액세스를 사용하는 것은 동기화 된 코드를 통해 이러한 변수에 액세스하는 것보다 효율적이지만 메모리 일관성 오류를 피하기 위해 프로그래머의 더 많은주의가 필요합니다.추가 노력이 가치가 있는지 여부는 응용 프로그램의 크기와 복잡성에 달려 있습니다.

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