문제

private static Callback callback;

public Foo()
{
    super(getCallback());
}

private static Callback getCallback()
{
    callback = new Callback();
    return callback;
}

생성자 foo ()는 여러 스레드에서 잠재적으로 호출 할 수 있습니다. 내 우려는 개인 정적 필드 '콜백'과 정적 메소드 'getCallback ()'에 관한 것입니다.

볼 수 있듯이 'getCallback ()'가 호출 될 때마다 정적 필드 '콜백'에 새 값을 할당합니다.

나의 추측 키워드이기 때문에 스레드 안전하지 않다는 것입니다. 공전 항상 인스턴스가 아닌 클래스에 첨부되므로 FOO의 정적 필드 '콜백'은 다른 foo ()를 구성하는 다른 스레드에 의해 잠재적으로 덮어 쓸 수 있습니다. 이 올바른지?

내가 틀렸다면 저를 바로 잡으십시오. 감사!

편집 : 내 의도는 수업의 어딘가에 '콜백'을 유지하는 것입니다. 그래서 나중에 재사용 할 수 있습니다. 그러나 Foo가 '콜백'을 의무화 할 수있는 생성자가있는 클래스에서 확장되기 때문에 이것은 쉽지 않습니다.

도움이 되었습니까?

해결책

그래 너가 옳아. 두 가지 인스턴스가 가능합니다 Foo 동일하게 끝납니다 CallBack 인스턴스 두 스레드가 입력 한 경우 getCallback() 메소드는 동시에 새로운 것을 할당합니다 CallBack 정적 필드에 다른 사람은 이미 이것을 수행했지만 아직 반환되지 않았습니다. 이 경우 가장 좋은 수정은 정적 필드를 갖지 않는 것입니다. 또는 만들기 getCallback() 동기화.

그러나 그것은 그다는 점에 유의하십시오 ~ 아니다 사실 만 static 키워드는 threadSafe가 아닌 코드를 결과합니다.

다른 팁

스레드 안전이 아닙니다. 이 대안을 시도하십시오.

옵션 1 : 여기서 모든 인스턴스는 동일한 콜백을 공유합니다.

private static final Callback callback = new Callback();

public Foo() {
    super(callback);
}

옵션 2 : 여기 각 인스턴스에는 자체 콜백이 있습니다.

public Foo() {
    super(new Callback());
}

두 경우 모두 생성자가 스레드 안전이지만 전체 클래스의 스레드 안전성은 콜백 구현에 따라 다릅니다. 상태가 변한 상태가 있다면 잠재적 인 문제가 발생할 수 있습니다. 콜백이 불변이라면 스레드 안전성이 있습니다.

콜백은 foo ()가 (같은 스레드에서도) 호출 될 때마다 새 값을 얻습니다. 코드가 무엇을 해야하는지 잘 모르겠습니다 (정적 변수를 한 번만 초기화하려면 (Singleton) GetCallback ()에서 여전히 null인지 확인해야합니다. 스레드 안전을 위해 동기화 된 사용을 사용하십시오.

나는 당신이 그것을 완벽하게 요약했다고 생각하지만, 당신이 달성하려는 것에 대한 자세한 내용은 문제를 해결하기 위해 제안을하는 것이 까다로울 것입니다.

명백한 질문 중 하나는 그렇습니다 callback 정적이어야합니까? 아니면 클래스의 기능을 위반하지 않고 인스턴스 필드로 안전하게 만들 수 있습니까?

나는 그것이 대답을 받았다는 것을 알고 있지만 왜 실제로 상세하지 않은 이유.

두 개의 스레드가 getCallback () 메소드를 호출하고 다음과 같이 줄을 실행할 수 있습니다.

  1. 스레드 1 -Callback = New Callback ();
  2. 스레드 2- 콜백 = 새 콜백 ();
  3. 스레드 1- return actioncallback;
  4. 스레드 2- 리턴 actioncallback;

이 경우 (2)에서 생성 된 콜백은 (3)과 (4) 모두에서 반환됩니다.

솔루션은 콜백이 클래스가 아닌 인스턴스에 특정한 경우 왜 콜백이 정적으로 정의되었는지 묻는 것 같습니다.

도움이되기를 바랍니다.

당신이하려는 것은 싱글 톤 패턴이라고 불리는 것입니다. 검색을 수행하면 가능한 경우 일반적 으로이 패턴을 피하는 것이 좋은 아이디어인지 알 수 있지만 필요한 경우 다음을 수행 할 수 있습니다.

private static final Callback CALLBACK= new Callback();

또는 게으른 싱글 톤이 필요하면 할 수 있습니다.

public class Foo {
   class CallbackHolder {
       static final Callback CALLBACK= new Callback();
   }

   public static Callback getCallback() {
      return CallbackHolder.CALLBACK;
   }

public Foo() {
    super(getCallback());
}

두 구현 모두 스레드 안전합니다.

스레드 당 하나의 콜백, 객체 당 하나 또는 진정한 싱글 톤을 원하십니까?

다른 변형을 수행하는 방법에 대한 스케치 - 내 머리 꼭대기에서 문자 그대로 가져 가지 마십시오 :)

콜백에 처리해야 할 예외가 발생할 수있는 사소한 생성자가 있다고 가정했습니다. 사소한 생성자 인 경우이 모든 것을 많이 단순화 할 수 있습니다.

스레드 당 하나 :

  private static ThreadLocal<Callback> callback;

  public Foo()
  {
      super(getCallback());
  }

  private static Callback getCallback()
  {
      if ( callback.get() == null ) 
          callback.set(new Callback());
      return callback.get();
  }

모든 스레드에 대한 단일 콜백 :

  private final static Callback callback;

  static {
      callback = new Callback(); 
  }

  public Foo()
  {
      super(getCallback());
  }

  private static Callback getCallback()
  {
      return callback;
  }

완료를 위해 객체 당 하나의 콜백 :

  private Callback callback;

  public Foo()
  {
      super(getCallback());
  }

  private Callback getCallback()
  {
      callback = new Callback();
      return callback;
  }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top