2009-06-01 3 views
3
private static Callback callback; 

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

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

생성자 Foo()는 잠재적으로 여러 스레드에서 호출 될 수 있습니다. 내 관심사는 개인 정적 필드 '콜백'및 정적 메서드 'getCallback()'입니다.다음 코드를 검토하면 도움이 될까요?

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

추측 키워드 정적는 항상 클래스가 아니라 인스턴스에 연결되어 있기 때문에, 그래서 수단을 스레드로부터 안전하지 않습니다 즉, 푸의 정적 필드 '콜백'는 잠재적으로 다른 덮어 쓰기 가능 스레드는 다른 Foo()를 생성합니다. 이 올바른지?

내가 잘못하면 저를 교정하십시오. 감사!

편집 : 의도는 클래스의 어딘가에 '콜백'을 유지하는 것이므로 나중에 다시 사용할 수 있습니다. 그러나 Foo는 '콜백'을 전달하는 생성자가있는 클래스에서 확장되므로 전달하기가 쉽지 않습니다.

+1

좋은 질문입니다. 이러한 문제는 논리적으로 스스로 생각하기가 어렵습니다. –

+0

컴파일되지 않습니다. actionCallback은 어디에서 왔는가? 일반적으로, 혼란을 원하지 않는 한 생성자를 통해 정적 필드를 초기화하지 마십시오. –

+0

죄송합니다. 'actionCallback'이 (가) '콜백'이었습니다. 내 의도는 클래스의 어딘가에서 '콜백'을 유지하는 것이므로 나중에 다시 사용할 수 있습니다. 그러나 Foo는 '콜백'을 전달하는 생성자가있는 클래스에서 확장되므로 전달하기가 쉽지 않습니다. – His

답변

6

네, 맞습니다. Foo의 두 인스턴스가 두 스레드가 getCallback() 메서드를 동시에 입력 할 때 CallBack 인스턴스로 끝날 수 있으며 다른 하나는 정적 필드에 새 CallBack을 할당하고 다른 하나는 이미 완료했지만 아직 반환되지 않은 경우는 하나가 가능합니다. 이 경우 가장 좋은 수정은 정적 필드를 가지지 않기 때문에 목적을 달성하지 못하기 때문입니다. 또는 getCallback()을 동기화하십시오.

그러나 이 아니고 static 키워드 만 스레드 세이프가 아닌 코드가된다는 사실은입니다.

3

콜백은 Foo()가 호출 될 때마다 (동일한 스레드에서도) 새 값을 가져옵니다. 정적 변수를 한 번만 (싱글 톤) 초기화하려면 getCallback()에서 null인지 여전히 확인해야하며 actionCallback은 무엇입니까?). 스레드로부터 안전하게하려면 synchronized를 사용하십시오.

2

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

하나의 명백한 질문은 callback이 정적이어야합니까? 또는 클래스의 기능을 손상시키지 않고 인스턴스 필드를 안전하게 만들 수 있습니까?

5

스레드로부터 안전하지 않습니다. 보십시오이 대안 :

옵션 1 : 여기에 모든 인스턴스는 같은 콜백에게

private static final Callback callback = new Callback(); 

public Foo() { 
    super(callback); 
} 

옵션 2를 공유 : 여기에 각 인스턴스는 자신의 콜백이 두 경우 모두, 비록

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

참고있다 생성자가 스레드로부터 안전 할 경우 클래스 전체의 스레드 안전성은 콜백 구현에 따라 다릅니다. 가변 상태 인 경우 문제가 발생할 수 있습니다. 콜백이 불변 인 경우에는 스레드 안전성을가집니다.

2

나는 답변을 받았지만 실제로는 상세하지 않은 이유를 알고 있습니다.; 콜백 = 새로운 콜백() -

  1. 스레드 1을 다음과 같이

    그것은 두 스레드가 getCallback() 메소드를 호출들은 라인을 실행할 수

  2. 스레드 2 - 콜백 = 새 콜백();
  3. 스레드 1 - return actionCallback;
  4. 스레드 2 - return actionCallback; 콜백 staticly이 경우 정의 된 이유는이 경우

는, (2)에서 생성 된 콜백은 모두 (3)에 반환되는 및 (4)

이 솔루션은 요구하는 것 같다 클래스가 아닌 인스턴스에만 해당됩니다.

도움이 되었기를 바랍니다.

1

당신이하려고하는 것을 싱글 톤 패턴이라고 부릅니다. 검색을 수행 할 수 있다면 가능하면이 패턴을 피하는 것이 일반적으로 좋은 이유를 알 수 있습니다. 그러나 필요한 경우 다음을 수행 할 수 있습니다.

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()); 
} 

할 수 있습니다.

1

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

다른 변형을 수행하는 방법에 대한 몇 가지 스케치 - 내 머리의 상단에서 역시 그대로이 적용되지 않습니다 :

내가 콜백이 사소 생성자를 갖는다 고 가정 한 점에 유의하시기 바랍니다 처리해야 할 예외를 던질 수 있습니다. 사소한 생성자라면이 모든 것을 간단하게 처리 할 수 ​​있습니다. completness에 대한

private final static Callback callback; 

    static { 
     callback = new Callback(); 
    } 

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

    private static Callback getCallback() 
    { 
     return callback; 
    } 

그리고, 객체 당 하나의 콜백 : 스레드 당

하나 :

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 Callback callback; 

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

    private Callback getCallback() 
    { 
     callback = new Callback(); 
     return callback; 
    } 
관련 문제