2016-08-25 4 views
0

나는 정적 값의 위험한 초기화가있는 라이브러리를 사용하고 있습니다 (예 : 클래스가 최소값으로 제거되었습니다) :은 FindBugs 'JLM_JSR166_UTILCONCURRENT_MONITORENTER'이 경우 안전합니다.

public TheirBaseClass { 
    public static String PathToUse = null; 

    public BaseClass(){ 
     PathToUse = "Configured"; 

     // ... 
     // do some other stuff with other side effects 
     // ... 
    } 
} 

값을 ConfigValue (일부 부작용을 피하기 위해)을 인스턴스화하지 않고 읽으려는 경우가 있습니다.

Paths.get(TheirBaseClass.PathToUse).toFile().... 

이 정적에 액세스 할 때 나는이 클래스를 사용하는 데 필요한하고 있기 때문에, 나는 그것에서 상속, 그 초기화를 보장하는 조치를 취하려고 찾고 오전 NullPointerException

이 자리를 차지하게됩니다.

MyBaseClass.Initialize(); 
Paths.get(MyBaseClass.PathToUse).toFile().... 

날 수 있습니다

public MyBaseClass extends TheirBaseClass{ 

    private static final AtomicBoolean isInitialized = new AtomicBoolean(false); 

    static { 
     MyBaseClass.Initialize(); 
    } 

    public static void Initialize(){ 
     // FindBugs does not like me synchronizing on a concurrent object 
     synchronized(isInitialized){ 
      if(isInitialized.get()){ 
       return; 
      } 
      new TheirBaseClass(); 
      isInitialized.set(true); 
     } 
    } 

    public MyBaseClass(){ 
     super(); 
    } 

} 

이 합리적으로 잘 작동하는 것 같군 (우리가 꾸게 다른 팬텀 결함을 해결합니다). 그것은 TheirBaseClass이 자연스럽게 작동 할 수있게 해주는 반면, 내가 필요로하는 몇 가지 경우에 초기화를 안전하게 할 수있게 해줍니다.

그러나이 코드에 대해 FindBugs를 실행하면 JLM_JSR166_UTILCONCURRENT_MONITORENTER이됩니다. 설명을 읽은 후, 나는

  1. 내가이 경우에 무시의 안전을 생각한다 (그러나 의심의 여지가) ... 다른 사람이 값을 변경할 수 있기 때문에 AtomicBoolean의 사용은 위험 할 수 있다고 동의하지만,
  2. 나는 일반적으로

가 실제로 위험한 일을하고 있습니까 (및 단지 그것을 볼 수 없습니다) 대신에 무시 마커를 넣어보다 코드를 다시 작성하는 것을 선호? 이 작업을 수행하는 더 좋은 방법이 있습니까?

불행히도 다른 TheirBaseClass을 사용하는 것은 옵션이 아닙니다.

당신은 쉽게 적응 찾을 수 있습니다

답변

1

관련 lazy holder idiom :이 클래스 로딩은 한 번 발생 및 동기화는 사실을 사용

public MyBaseClass { 
    private static class Initializer { 
    static { 
     new TheirBaseClass(); 
    } 

    // Doesn't actually do anything; merely provides an expression 
    // to cause the Initializer class to be loaded. 
    private static void ensureInitialized() {} 
    } 

    { 
    Initializer.ensureInitialized(); 
    } 

    // Rest of the class. 
} 

(단일 클래스 로더 내에서). MyBaseClass을 인스턴스화 할 때만 발생합니다.

+0

필자는 나의 예에서 큰 실수를 저질렀다고 생각한다. 나는 그들의베이스 클래스를 확장하지 않았다. –

+0

나는 이것을 숙고해야만했다. 이미'게으른 홀더'를 구현하고 있습니다. 귀하의 대답은 정확하지만, 그 혼동은 부울 주위에서 발생하는 것 같습니다 : 그것은 완전히 불필요합니다. 특정 케이스에 대해 소개했지만이 경우 점점 더 많은 리팩토링을 수행 한 것으로 보입니다. –

+0

부울은 불필요합니다. * 이니셜 라이저를 비공개로 만들면 * –